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

org.bouncycastle.pqc.crypto.newhope.NewHope 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.crypto.newhope;

import java.security.SecureRandom;

import org.bouncycastle.crypto.digests.SHA3Digest;

/**
 * This implementation is based heavily on the C reference implementation from https://cryptojedi.org/crypto/index.shtml.
 */
class NewHope
{
    private static final boolean STATISTICAL_TEST = false;

    public static final int AGREEMENT_SIZE = 32;
    public static final int POLY_SIZE = Params.N;
    public static final int SENDA_BYTES = Params.POLY_BYTES + Params.SEED_BYTES;
    public static final int SENDB_BYTES = Params.POLY_BYTES + Params.REC_BYTES;

    public static void keygen(SecureRandom rand, byte[] send, short[] sk)
    {
        byte[] seed = new byte[Params.SEED_BYTES];
        rand.nextBytes(seed);
        
        sha3(seed);     // don't expose RNG output

        short[] a = new short[Params.N];
        generateA(a, seed);

        byte[] noiseSeed = new byte[32];
        rand.nextBytes(noiseSeed);

        Poly.getNoise(sk, noiseSeed, (byte)0);
        Poly.toNTT(sk);

        short[] e = new short[Params.N];
        Poly.getNoise(e, noiseSeed, (byte)1);
        Poly.toNTT(e);

        short[] r = new short[Params.N];
        Poly.pointWise(a, sk, r);

        short[] pk = new short[Params.N];
        Poly.add(r, e, pk);

        encodeA(send, pk, seed);
    }

    public static void sharedB(SecureRandom rand, byte[] sharedKey, byte[] send, byte[] received)
    {
        short[] pkA = new short[Params.N];
        byte[] seed = new byte[Params.SEED_BYTES];
        decodeA(pkA, seed, received);

        short[] a = new short[Params.N];
        generateA(a, seed);

        byte[] noiseSeed = new byte[32];
        rand.nextBytes(noiseSeed);

        short[] sp = new short[Params.N];
        Poly.getNoise(sp, noiseSeed, (byte)0);
        Poly.toNTT(sp);

        short[] ep = new short[Params.N];
        Poly.getNoise(ep, noiseSeed, (byte)1);
        Poly.toNTT(ep);

        short[] bp = new short[Params.N];
        Poly.pointWise(a, sp, bp);
        Poly.add(bp, ep, bp);

        short[] v = new short[Params.N];
        Poly.pointWise(pkA, sp, v);
        Poly.fromNTT(v);

        short[] epp = new short[Params.N];
        Poly.getNoise(epp, noiseSeed, (byte)2);
        Poly.add(v, epp, v);

        short[] c = new short[Params.N];
        ErrorCorrection.helpRec(c, v, noiseSeed, (byte)3);

        encodeB(send, bp, c);

        ErrorCorrection.rec(sharedKey, v, c);

        if (!STATISTICAL_TEST)
        {
            sha3(sharedKey);
        }
    }

    public static void sharedA(byte[] sharedKey, short[] sk, byte[] received)
    {
        short[] bp = new short[Params.N];
        short[] c = new short[Params.N];
        decodeB(bp, c, received);

        short[] v = new short[Params.N];
        Poly.pointWise(sk, bp, v);
        Poly.fromNTT(v);

        ErrorCorrection.rec(sharedKey, v, c);

        if (!STATISTICAL_TEST)
        {
            sha3(sharedKey);
        }
    }

    static void decodeA(short[] pk, byte[] seed, byte[] r)
    {
        Poly.fromBytes(pk, r);
        System.arraycopy(r, Params.POLY_BYTES, seed, 0, Params.SEED_BYTES);
    }

    static void decodeB(short[] b, short[] c, byte[] r)
    {
        Poly.fromBytes(b, r);

        for (int i = 0; i < Params.N / 4; ++i)
        {
            int j = 4 * i;
            int ri = r[Params.POLY_BYTES + i] & 0xFF;
            c[j + 0] = (short)(ri & 0x03);
            c[j + 1] = (short)((ri >>> 2) & 0x03);
            c[j + 2] = (short)((ri >>> 4) & 0x03);
            c[j + 3] = (short)(ri >>> 6);
        }
    }

    static void encodeA(byte[] r, short[] pk, byte[] seed)
    {
        Poly.toBytes(r, pk);
        System.arraycopy(seed, 0, r, Params.POLY_BYTES, Params.SEED_BYTES);        
    }

    static void encodeB(byte[] r, short[] b, short[] c)
    {
        Poly.toBytes(r, b);

        for (int i = 0; i < Params.N / 4; ++i)
        {
            int j = 4 * i;
            r[Params.POLY_BYTES + i] = (byte)(c[j] | (c[j + 1] << 2) | (c[j + 2] << 4) | (c[j + 3] << 6));
        }
    }

    static void generateA(short[] a, byte[] seed)
    {
        Poly.uniform(a, seed);
    }
    
    static void sha3(byte[] sharedKey)
    {
        SHA3Digest d = new SHA3Digest(256);
        d.update(sharedKey, 0, 32);
        d.doFinal(sharedKey, 0);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy