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

org.bouncycastle.pqc.legacy.crypto.ntru.NTRUSigner Maven / Gradle / Ivy

Go to download

The Bouncy Castle Crypto package is a Java implementation of cryptographic algorithms. This jar contains JCE provider and lightweight API for the Bouncy Castle Cryptography APIs for Java 1.8 and later with debug enabled.

The newest version!
package org.bouncycastle.pqc.legacy.crypto.ntru;

import java.nio.ByteBuffer;

import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.Digest;
import org.bouncycastle.pqc.legacy.math.ntru.polynomial.IntegerPolynomial;
import org.bouncycastle.pqc.legacy.math.ntru.polynomial.Polynomial;

/**
* Signs, verifies data and generates key pairs.
* @deprecated the NTRUSigner algorithm was broken in 2012 by Ducas and Nguyen. See
* 
* https://www.di.ens.fr/~ducas/NTRUSign_Cryptanalysis/DucasNguyen_Learning.pdf
* for details.
*/
public class NTRUSigner
{
    private NTRUSigningParameters params;
    private Digest hashAlg;
    private NTRUSigningPrivateKeyParameters signingKeyPair;
    private NTRUSigningPublicKeyParameters verificationKey;

    /**
     * Constructs a new instance with a set of signature parameters.
     *
     * @param params signature parameters
     */
    public NTRUSigner(NTRUSigningParameters params)
    {
        this.params = params;
    }

    /**
     * Resets the engine for signing a message.
     *
     * @param forSigning
     * @param params
     */
    public void init(boolean forSigning, CipherParameters params)
    {
        if (forSigning)
        {
            this.signingKeyPair = (NTRUSigningPrivateKeyParameters)params;
        }
        else
        {
            this.verificationKey = (NTRUSigningPublicKeyParameters)params;
        }
        hashAlg = this.params.hashAlg;
        hashAlg.reset();
    }

    /**
      * Adds data to sign or verify.
      *
      * @param b data
      */
     public void update(byte b)
     {
         if (hashAlg == null)
         {
             throw new IllegalStateException("Call initSign or initVerify first!");
         }

         hashAlg.update(b);
     }

    /**
     * Adds data to sign or verify.
     *
     * @param m data
     * @param off offset
     * @param length number of bytes
     */
    public void update(byte[] m, int off, int length)
    {
        if (hashAlg == null)
        {
            throw new IllegalStateException("Call initSign or initVerify first!");
        }

        hashAlg.update(m, off, length);
    }

    /**
     * Adds data to sign and computes a signature over this data and any data previously added via {@link #update(byte[], int, int)}.
     *
     * @return a signature
     * @throws IllegalStateException if initSign was not called
     */
    public byte[] generateSignature()
    {
        if (hashAlg == null || signingKeyPair == null)
        {
            throw new IllegalStateException("Call initSign first!");
        }

        byte[] msgHash = new byte[hashAlg.getDigestSize()];

        hashAlg.doFinal(msgHash, 0);
        return signHash(msgHash, signingKeyPair);
    }

    private byte[] signHash(byte[] msgHash, NTRUSigningPrivateKeyParameters kp)
    {
        int r = 0;
        IntegerPolynomial s;
        IntegerPolynomial i;

        NTRUSigningPublicKeyParameters kPub = kp.getPublicKey();
        do
        {
            r++;
            if (r > params.signFailTolerance)
            {
                throw new IllegalStateException("Signing failed: too many retries (max=" + params.signFailTolerance + ")");
            }
            i = createMsgRep(msgHash, r);
            s = sign(i, kp);
        }
        while (!verify(i, s, kPub.h));

        byte[] rawSig = s.toBinary(params.q);
        ByteBuffer sbuf = ByteBuffer.allocate(rawSig.length + 4);
        sbuf.put(rawSig);
        sbuf.putInt(r);
        return sbuf.array();
    }

    private IntegerPolynomial sign(IntegerPolynomial i, NTRUSigningPrivateKeyParameters kp)
    {
        int N = params.N;
        int q = params.q;
        int perturbationBases = params.B;

        NTRUSigningPrivateKeyParameters kPriv = kp;
        NTRUSigningPublicKeyParameters kPub = kp.getPublicKey();

        IntegerPolynomial s = new IntegerPolynomial(N);
        int iLoop = perturbationBases;
        while (iLoop >= 1)
        {
            Polynomial f = kPriv.getBasis(iLoop).f;
            Polynomial fPrime = kPriv.getBasis(iLoop).fPrime;

            IntegerPolynomial y = f.mult(i);
            y.div(q);
            y = fPrime.mult(y);

            IntegerPolynomial x = fPrime.mult(i);
            x.div(q);
            x = f.mult(x);

            IntegerPolynomial si = y;
            si.sub(x);
            s.add(si);

            IntegerPolynomial hi = (IntegerPolynomial)kPriv.getBasis(iLoop).h.clone();
            if (iLoop > 1)
            {
                hi.sub(kPriv.getBasis(iLoop - 1).h);
            }
            else
            {
                hi.sub(kPub.h);
            }
            i = si.mult(hi, q);

            iLoop--;
        }

        Polynomial f = kPriv.getBasis(0).f;
        Polynomial fPrime = kPriv.getBasis(0).fPrime;

        IntegerPolynomial y = f.mult(i);
        y.div(q);
        y = fPrime.mult(y);

        IntegerPolynomial x = fPrime.mult(i);
        x.div(q);
        x = f.mult(x);

        y.sub(x);
        s.add(y);
        s.modPositive(q);
        return s;
    }

    /**
     * Verifies a signature for any data previously added via {@link #update(byte[], int, int)}.
     *
     * @param sig a signature
     * @return whether the signature is valid
     * @throws IllegalStateException if initVerify was not called
     */
    public boolean verifySignature(byte[] sig)
    {
        if (hashAlg == null || verificationKey == null)
        {
            throw new IllegalStateException("Call initVerify first!");
        }

        byte[] msgHash = new byte[hashAlg.getDigestSize()];

        hashAlg.doFinal(msgHash, 0);

        return verifyHash(msgHash, sig, verificationKey);
    }

    private boolean verifyHash(byte[] msgHash, byte[] sig, NTRUSigningPublicKeyParameters pub)
    {
        ByteBuffer sbuf = ByteBuffer.wrap(sig);
        byte[] rawSig = new byte[sig.length - 4];
        sbuf.get(rawSig);
        IntegerPolynomial s = IntegerPolynomial.fromBinary(rawSig, params.N, params.q);
        int r = sbuf.getInt();
        return verify(createMsgRep(msgHash, r), s, pub.h);
    }

    private boolean verify(IntegerPolynomial i, IntegerPolynomial s, IntegerPolynomial h)
    {
        int q = params.q;
        double normBoundSq = params.normBoundSq;
        double betaSq = params.betaSq;

        IntegerPolynomial t = h.mult(s, q);
        t.sub(i);
        long centeredNormSq = (long)(s.centeredNormSq(q) + betaSq * t.centeredNormSq(q));
        return centeredNormSq <= normBoundSq;
    }

    protected IntegerPolynomial createMsgRep(byte[] msgHash, int r)
    {
        int N = params.N;
        int q = params.q;

        int c = 31 - Integer.numberOfLeadingZeros(q);
        int B = (c + 7) / 8;
        IntegerPolynomial i = new IntegerPolynomial(N);

        ByteBuffer cbuf = ByteBuffer.allocate(msgHash.length + 4);
        cbuf.put(msgHash);
        cbuf.putInt(r);
        NTRUSignerPrng prng = new NTRUSignerPrng(cbuf.array(), params.hashAlg);

        for (int t = 0; t < N; t++)
        {
            byte[] o = prng.nextBytes(B);
            int hi = o[o.length - 1];
            hi >>= 8 * B - c;
            hi <<= 8 * B - c;
            o[o.length - 1] = (byte)hi;

            ByteBuffer obuf = ByteBuffer.allocate(4);
            obuf.put(o);
            obuf.rewind();
            // reverse byte order so it matches the endianness of java ints
            i.coeffs[t] = Integer.reverseBytes(obuf.getInt());
        }
        return i;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy