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

com.bouncycastle.math.ec.Tnaf Maven / Gradle / Ivy

The newest version!
package com.bouncycastle.math.ec;

import java.math.BigInteger;

/**
 * Class holding methods for point multiplication based on the window
 * τ-adic nonadjacent form (WTNAF). The algorithms are based on the
 * paper "Improved Algorithms for Arithmetic on Anomalous Binary Curves"
 * by Jerome A. Solinas. The paper first appeared in the Proceedings of
 * Crypto 1997.
 */
class Tnaf
{
    private static final BigInteger MINUS_ONE = ECConstants.ONE.negate();
    private static final BigInteger MINUS_TWO = ECConstants.TWO.negate();
    private static final BigInteger MINUS_THREE = ECConstants.THREE.negate();

    /**
     * The window width of WTNAF. The standard value of 4 is slightly less
     * than optimal for running time, but keeps space requirements for
     * precomputation low. For typical curves, a value of 5 or 6 results in
     * a better running time. When changing this value, the
     * αu's must be computed differently, see
     * e.g. "Guide to Elliptic Curve Cryptography", Darrel Hankerson,
     * Alfred Menezes, Scott Vanstone, Springer-Verlag New York Inc., 2004,
     * p. 121-122
     */
    public static final byte WIDTH = 4;

    /**
     * 24
     */
    public static final byte POW_2_WIDTH = 16;

    /**
     * The αu's for a=0 as an array
     * of ZTauElements.
     */
    public static final ZTauElement[] alpha0 = {
        null,
        new ZTauElement(ECConstants.ONE, ECConstants.ZERO), null,
        new ZTauElement(MINUS_THREE, MINUS_ONE), null,
        new ZTauElement(MINUS_ONE, MINUS_ONE), null,
        new ZTauElement(ECConstants.ONE, MINUS_ONE), null
    };

    /**
     * The αu's for a=0 as an array
     * of TNAFs.
     */
    public static final byte[][] alpha0Tnaf = {
        null, {1}, null, {-1, 0, 1}, null, {1, 0, 1}, null, {-1, 0, 0, 1}
    };

    /**
     * The αu's for a=1 as an array
     * of ZTauElements.
     */
    public static final ZTauElement[] alpha1 = {null,
        new ZTauElement(ECConstants.ONE, ECConstants.ZERO), null,
        new ZTauElement(MINUS_THREE, ECConstants.ONE), null,
        new ZTauElement(MINUS_ONE, ECConstants.ONE), null,
        new ZTauElement(ECConstants.ONE, ECConstants.ONE), null
    };

    /**
     * The αu's for a=1 as an array
     * of TNAFs.
     */
    public static final byte[][] alpha1Tnaf = {
        null, {1}, null, {-1, 0, 1}, null, {1, 0, 1}, null, {-1, 0, 0, -1}
    };

    /**
     * Computes the norm of an element λ of
     * Z[τ].
     * @param mu The parameter μ of the elliptic curve.
     * @param lambda The element λ of
     * Z[τ].
     * @return The norm of λ.
     */
    public static BigInteger norm(final byte mu, ZTauElement lambda)
    {
        BigInteger norm;

        // s1 = u^2
        BigInteger s1 = lambda.u.multiply(lambda.u);

        // s2 = u * v
        BigInteger s2 = lambda.u.multiply(lambda.v);

        // s3 = 2 * v^2
        BigInteger s3 = lambda.v.multiply(lambda.v).shiftLeft(1);

        if (mu == 1)
        {
            norm = s1.add(s2).add(s3);
        }
        else if (mu == -1)
        {
            norm = s1.subtract(s2).add(s3);
        }
        else
        {
            throw new IllegalArgumentException("mu must be 1 or -1");
        }

        return norm;
    }

    /**
     * Computes the norm of an element λ of
     * R[τ], where λ = u + vτ
     * and u and u are real numbers (elements of
     * R). 
     * @param mu The parameter μ of the elliptic curve.
     * @param u The real part of the element λ of
     * R[τ].
     * @param v The τ-adic part of the element
     * λ of R[τ].
     * @return The norm of λ.
     */
    public static SimpleBigDecimal norm(final byte mu, SimpleBigDecimal u,
            SimpleBigDecimal v)
    {
        SimpleBigDecimal norm;

        // s1 = u^2
        SimpleBigDecimal s1 = u.multiply(u);

        // s2 = u * v
        SimpleBigDecimal s2 = u.multiply(v);

        // s3 = 2 * v^2
        SimpleBigDecimal s3 = v.multiply(v).shiftLeft(1);

        if (mu == 1)
        {
            norm = s1.add(s2).add(s3);
        }
        else if (mu == -1)
        {
            norm = s1.subtract(s2).add(s3);
        }
        else
        {
            throw new IllegalArgumentException("mu must be 1 or -1");
        }

        return norm;
    }

    /**
     * Rounds an element λ of R[τ]
     * to an element of Z[τ], such that their difference
     * has minimal norm. λ is given as
     * λ = λ0 + λ1τ.
     * @param lambda0 The component λ0.
     * @param lambda1 The component λ1.
     * @param mu The parameter μ of the elliptic curve. Must
     * equal 1 or -1.
     * @return The rounded element of Z[τ].
     * @throws IllegalArgumentException if lambda0 and
     * lambda1 do not have same scale.
     */
    public static ZTauElement round(SimpleBigDecimal lambda0,
            SimpleBigDecimal lambda1, byte mu)
    {
        int scale = lambda0.getScale();
        if (lambda1.getScale() != scale)
        {
            throw new IllegalArgumentException("lambda0 and lambda1 do not " +
                    "have same scale");
        }

        if (!((mu == 1) || (mu == -1)))
        {
            throw new IllegalArgumentException("mu must be 1 or -1");
        }

        BigInteger f0 = lambda0.round();
        BigInteger f1 = lambda1.round();

        SimpleBigDecimal eta0 = lambda0.subtract(f0);
        SimpleBigDecimal eta1 = lambda1.subtract(f1);

        // eta = 2*eta0 + mu*eta1
        SimpleBigDecimal eta = eta0.add(eta0);
        if (mu == 1)
        {
            eta = eta.add(eta1);
        }
        else
        {
            // mu == -1
            eta = eta.subtract(eta1);
        }

        // check1 = eta0 - 3*mu*eta1
        // check2 = eta0 + 4*mu*eta1
        SimpleBigDecimal threeEta1 = eta1.add(eta1).add(eta1);
        SimpleBigDecimal fourEta1 = threeEta1.add(eta1);
        SimpleBigDecimal check1;
        SimpleBigDecimal check2;
        if (mu == 1)
        {
            check1 = eta0.subtract(threeEta1);
            check2 = eta0.add(fourEta1);
        }
        else
        {
            // mu == -1
            check1 = eta0.add(threeEta1);
            check2 = eta0.subtract(fourEta1);
        }

        byte h0 = 0;
        byte h1 = 0;

        // if eta >= 1
        if (eta.compareTo(ECConstants.ONE) >= 0)
        {
            if (check1.compareTo(MINUS_ONE) < 0)
            {
                h1 = mu;
            }
            else
            {
                h0 = 1;
            }
        }
        else
        {
            // eta < 1
            if (check2.compareTo(ECConstants.TWO) >= 0)
            {
                h1 = mu;
            }
        }

        // if eta < -1
        if (eta.compareTo(MINUS_ONE) < 0)
        {
            if (check1.compareTo(ECConstants.ONE) >= 0)
            {
                h1 = (byte)-mu;
            }
            else
            {
                h0 = -1;
            }
        }
        else
        {
            // eta >= -1
            if (check2.compareTo(MINUS_TWO) < 0)
            {
                h1 = (byte)-mu;
            }
        }

        BigInteger q0 = f0.add(BigInteger.valueOf(h0));
        BigInteger q1 = f1.add(BigInteger.valueOf(h1));
        return new ZTauElement(q0, q1);
    }

    /**
     * Approximate division by n. For an integer
     * k, the value λ = s k / n is
     * computed to c bits of accuracy.
     * @param k The parameter k.
     * @param s The curve parameter s0 or
     * s1.
     * @param vm The Lucas Sequence element Vm.
     * @param a The parameter a of the elliptic curve.
     * @param m The bit length of the finite field
     * Fm.
     * @param c The number of bits of accuracy, i.e. the scale of the returned
     * SimpleBigDecimal.
     * @return The value λ = s k / n computed to
     * c bits of accuracy.
     */
    public static SimpleBigDecimal approximateDivisionByN(BigInteger k,
            BigInteger s, BigInteger vm, byte a, int m, int c)
    {
        int _k = (m + 5)/2 + c;
        BigInteger ns = k.shiftRight(m - _k - 2 + a);

        BigInteger gs = s.multiply(ns);

        BigInteger hs = gs.shiftRight(m);

        BigInteger js = vm.multiply(hs);

        BigInteger gsPlusJs = gs.add(js);
        BigInteger ls = gsPlusJs.shiftRight(_k-c);
        if (gsPlusJs.testBit(_k-c-1))
        {
            // round up
            ls = ls.add(ECConstants.ONE);
        }

        return new SimpleBigDecimal(ls, c);
    }

    /**
     * Computes the τ-adic NAF (non-adjacent form) of an
     * element λ of Z[τ].
     * @param mu The parameter μ of the elliptic curve.
     * @param lambda The element λ of
     * Z[τ].
     * @return The τ-adic NAF of λ.
     */
    public static byte[] tauAdicNaf(byte mu, ZTauElement lambda)
    {
        if (!((mu == 1) || (mu == -1)))
        {
            throw new IllegalArgumentException("mu must be 1 or -1");
        }
        
        BigInteger norm = norm(mu, lambda);

        // Ceiling of log2 of the norm 
        int log2Norm = norm.bitLength();

        // If length(TNAF) > 30, then length(TNAF) < log2Norm + 3.52
        int maxLength = log2Norm > 30 ? log2Norm + 4 : 34;

        // The array holding the TNAF
        byte[] u = new byte[maxLength];
        int i = 0;

        // The actual length of the TNAF
        int length = 0;

        BigInteger r0 = lambda.u;
        BigInteger r1 = lambda.v;

        while(!((r0.equals(ECConstants.ZERO)) && (r1.equals(ECConstants.ZERO))))
        {
            // If r0 is odd
            if (r0.testBit(0))
            {
                u[i] = (byte) ECConstants.TWO.subtract((r0.subtract(r1.shiftLeft(1))).mod(ECConstants.FOUR)).intValue();

                // r0 = r0 - u[i]
                if (u[i] == 1)
                {
                    r0 = r0.clearBit(0);
                }
                else
                {
                    // u[i] == -1
                    r0 = r0.add(ECConstants.ONE);
                }
                length = i;
            }
            else
            {
                u[i] = 0;
            }

            BigInteger t = r0;
            BigInteger s = r0.shiftRight(1);
            if (mu == 1)
            {
                r0 = r1.add(s);
            }
            else
            {
                // mu == -1
                r0 = r1.subtract(s);
            }

            r1 = t.shiftRight(1).negate();
            i++;
        }

        length++;

        // Reduce the TNAF array to its actual length
        byte[] tnaf = new byte[length];
        System.arraycopy(u, 0, tnaf, 0, length);
        return tnaf;
    }

    /**
     * Applies the operation τ() to an
     * ECPoint.F2m. 
     * @param p The ECPoint.F2m to which τ() is applied.
     * @return τ(p)
     */
    public static ECPoint.F2m tau(ECPoint.F2m p)
    {
        if (p.isInfinity())
        {
            return p;
        }

        ECFieldElement x = p.getX();
        ECFieldElement y = p.getY();

        return new ECPoint.F2m(p.getCurve(), x.square(), y.square(), p.isCompressed());
    }

    /**
     * Returns the parameter μ of the elliptic curve.
     * @param curve The elliptic curve from which to obtain μ.
     * The curve must be a Koblitz curve, i.e. a equals
     * 0 or 1 and b equals
     * 1. 
     * @return μ of the elliptic curve.
     * @throws IllegalArgumentException if the given ECCurve is not a Koblitz
     * curve.
     */
    public static byte getMu(ECCurve.F2m curve)
    {
        BigInteger a = curve.getA().toBigInteger();
        byte mu;

        if (a.equals(ECConstants.ZERO))
        {
            mu = -1;
        }
        else if (a.equals(ECConstants.ONE))
        {
            mu = 1;
        }
        else
        {
            throw new IllegalArgumentException("No Koblitz curve (ABC), " +
                    "TNAF multiplication not possible");
        }
        return mu;
    }

    /**
     * Calculates the Lucas Sequence elements Uk-1 and
     * Uk or Vk-1 and
     * Vk.
     * @param mu The parameter μ of the elliptic curve.
     * @param k The index of the second element of the Lucas Sequence to be
     * returned.
     * @param doV If set to true, computes Vk-1 and
     * Vk, otherwise Uk-1 and
     * Uk.
     * @return An array with 2 elements, containing Uk-1
     * and Uk or Vk-1
     * and Vk.
     */
    public static BigInteger[] getLucas(byte mu, int k, boolean doV)
    {
        if (!((mu == 1) || (mu == -1)))
        {
            throw new IllegalArgumentException("mu must be 1 or -1");
        }

        BigInteger u0;
        BigInteger u1;
        BigInteger u2;

        if (doV)
        {
            u0 = ECConstants.TWO;
            u1 = BigInteger.valueOf(mu);
        }
        else
        {
            u0 = ECConstants.ZERO;
            u1 = ECConstants.ONE;
        }

        for (int i = 1; i < k; i++)
        {
            // u2 = mu*u1 - 2*u0;
            BigInteger s = null;
            if (mu == 1)
            {
                s = u1;
            }
            else
            {
                // mu == -1
                s = u1.negate();
            }
            
            u2 = s.subtract(u0.shiftLeft(1));
            u0 = u1;
            u1 = u2;
//            System.out.println(i + ": " + u2);
//            System.out.println();
        }

        BigInteger[] retVal = {u0, u1};
        return retVal;
    }

    /**
     * Computes the auxiliary value tw. If the width is
     * 4, then for mu = 1, tw = 6 and for
     * mu = -1, tw = 10 
     * @param mu The parameter μ of the elliptic curve.
     * @param w The window width of the WTNAF.
     * @return the auxiliary value tw
     */
    public static BigInteger getTw(byte mu, int w)
    {
        if (w == 4)
        {
            if (mu == 1)
            {
                return BigInteger.valueOf(6);
            }
            else
            {
                // mu == -1
                return BigInteger.valueOf(10);
            }
        }
        else
        {
            // For w <> 4, the values must be computed
            BigInteger[] us = getLucas(mu, w, false);
            BigInteger twoToW = ECConstants.ZERO.setBit(w);
            BigInteger u1invert = us[1].modInverse(twoToW);
            BigInteger tw;
            tw = ECConstants.TWO.multiply(us[0]).multiply(u1invert).mod(twoToW);
//            System.out.println("mu = " + mu);
//            System.out.println("tw = " + tw);
            return tw;
        }
    }

    /**
     * Computes the auxiliary values s0 and
     * s1 used for partial modular reduction. 
     * @param curve The elliptic curve for which to compute
     * s0 and s1.
     * @throws IllegalArgumentException if curve is not a
     * Koblitz curve (Anomalous Binary Curve, ABC).
     */
    public static BigInteger[] getSi(ECCurve.F2m curve)
    {
        if (!curve.isKoblitz())
        {
            throw new IllegalArgumentException("si is defined for Koblitz curves only");
        }

        int m = curve.getM();
        int a = curve.getA().toBigInteger().intValue();
        byte mu = curve.getMu();
        int h = curve.getH().intValue();
        int index = m + 3 - a;
        BigInteger[] ui = getLucas(mu, index, false);

        BigInteger dividend0;
        BigInteger dividend1;
        if (mu == 1)
        {
            dividend0 = ECConstants.ONE.subtract(ui[1]);
            dividend1 = ECConstants.ONE.subtract(ui[0]);
        }
        else if (mu == -1)
        {
            dividend0 = ECConstants.ONE.add(ui[1]);
            dividend1 = ECConstants.ONE.add(ui[0]);
        }
        else
        {
            throw new IllegalArgumentException("mu must be 1 or -1");
        }

        BigInteger[] si = new BigInteger[2];

        if (h == 2)
        {
            si[0] = dividend0.shiftRight(1);
            si[1] = dividend1.shiftRight(1).negate();
        }
        else if (h == 4)
        {
            si[0] = dividend0.shiftRight(2);
            si[1] = dividend1.shiftRight(2).negate();
        }
        else
        {
            throw new IllegalArgumentException("h (Cofactor) must be 2 or 4");
        }

        return si;
    }

    /**
     * Partial modular reduction modulo
     * m - 1)/(τ - 1).
     * @param k The integer to be reduced.
     * @param m The bitlength of the underlying finite field.
     * @param a The parameter a of the elliptic curve.
     * @param s The auxiliary values s0 and
     * s1.
     * @param mu The parameter μ of the elliptic curve.
     * @param c The precision (number of bits of accuracy) of the partial
     * modular reduction.
     * @return ρ := k partmod (τm - 1)/(τ - 1)
     */
    public static ZTauElement partModReduction(BigInteger k, int m, byte a,
            BigInteger[] s, byte mu, byte c)
    {
        // d0 = s[0] + mu*s[1]; mu is either 1 or -1
        BigInteger d0;
        if (mu == 1)
        {
            d0 = s[0].add(s[1]);
        }
        else
        {
            d0 = s[0].subtract(s[1]);
        }

        BigInteger[] v = getLucas(mu, m, true);
        BigInteger vm = v[1];

        SimpleBigDecimal lambda0 = approximateDivisionByN(
                k, s[0], vm, a, m, c);
        
        SimpleBigDecimal lambda1 = approximateDivisionByN(
                k, s[1], vm, a, m, c);

        ZTauElement q = round(lambda0, lambda1, mu);

        // r0 = n - d0*q0 - 2*s1*q1
        BigInteger r0 = k.subtract(d0.multiply(q.u)).subtract(
                BigInteger.valueOf(2).multiply(s[1]).multiply(q.v));

        // r1 = s1*q0 - s0*q1
        BigInteger r1 = s[1].multiply(q.u).subtract(s[0].multiply(q.v));
        
        return new ZTauElement(r0, r1);
    }

    /**
     * Multiplies a {@link ECPoint.F2m ECPoint.F2m}
     * by a BigInteger using the reduced τ-adic
     * NAF (RTNAF) method.
     * @param p The ECPoint.F2m to multiply.
     * @param k The BigInteger by which to multiply p.
     * @return k * p
     */
    public static ECPoint.F2m multiplyRTnaf(ECPoint.F2m p, BigInteger k)
    {
        ECCurve.F2m curve = (ECCurve.F2m) p.getCurve();
        int m = curve.getM();
        byte a = (byte) curve.getA().toBigInteger().intValue();
        byte mu = curve.getMu();
        BigInteger[] s = curve.getSi();
        ZTauElement rho = partModReduction(k, m, a, s, mu, (byte)10);

        return multiplyTnaf(p, rho);
    }

    /**
     * Multiplies a {@link ECPoint.F2m ECPoint.F2m}
     * by an element λ of Z[τ]
     * using the τ-adic NAF (TNAF) method.
     * @param p The ECPoint.F2m to multiply.
     * @param lambda The element λ of
     * Z[τ].
     * @return λ * p
     */
    public static ECPoint.F2m multiplyTnaf(ECPoint.F2m p, ZTauElement lambda)
    {
        ECCurve.F2m curve = (ECCurve.F2m)p.getCurve();
        byte mu = curve.getMu();
        byte[] u = tauAdicNaf(mu, lambda);

        ECPoint.F2m q = multiplyFromTnaf(p, u);

        return q;
    }

    /**
    * Multiplies a {@link ECPoint.F2m ECPoint.F2m}
    * by an element λ of Z[τ]
    * using the τ-adic NAF (TNAF) method, given the TNAF
    * of λ.
    * @param p The ECPoint.F2m to multiply.
    * @param u The the TNAF of λ..
    * @return λ * p
    */
    public static ECPoint.F2m multiplyFromTnaf(ECPoint.F2m p, byte[] u)
    {
        ECCurve.F2m curve = (ECCurve.F2m)p.getCurve();
        ECPoint.F2m q = (ECPoint.F2m) curve.getInfinity();
        for (int i = u.length - 1; i >= 0; i--)
        {
            q = tau(q);
            if (u[i] == 1)
            {
                q = (ECPoint.F2m)q.addSimple(p);
            }
            else if (u[i] == -1)
            {
                q = (ECPoint.F2m)q.subtractSimple(p);
            }
        }
        return q;
    }

    /**
     * Computes the [τ]-adic window NAF of an element
     * λ of Z[τ].
     * @param mu The parameter μ of the elliptic curve.
     * @param lambda The element λ of
     * Z[τ] of which to compute the
     * [τ]-adic NAF.
     * @param width The window width of the resulting WNAF.
     * @param pow2w 2width.
     * @param tw The auxiliary value tw.
     * @param alpha The αu's for the window width.
     * @return The [τ]-adic window NAF of
     * λ.
     */
    public static byte[] tauAdicWNaf(byte mu, ZTauElement lambda,
            byte width, BigInteger pow2w, BigInteger tw, ZTauElement[] alpha)
    {
        if (!((mu == 1) || (mu == -1)))
        {
            throw new IllegalArgumentException("mu must be 1 or -1");
        }

        BigInteger norm = norm(mu, lambda);

        // Ceiling of log2 of the norm 
        int log2Norm = norm.bitLength();

        // If length(TNAF) > 30, then length(TNAF) < log2Norm + 3.52
        int maxLength = log2Norm > 30 ? log2Norm + 4 + width : 34 + width;

        // The array holding the TNAF
        byte[] u = new byte[maxLength];

        // 2^(width - 1)
        BigInteger pow2wMin1 = pow2w.shiftRight(1);

        // Split lambda into two BigIntegers to simplify calculations
        BigInteger r0 = lambda.u;
        BigInteger r1 = lambda.v;
        int i = 0;

        // while lambda <> (0, 0)
        while (!((r0.equals(ECConstants.ZERO))&&(r1.equals(ECConstants.ZERO))))
        {
            // if r0 is odd
            if (r0.testBit(0))
            {
                // uUnMod = r0 + r1*tw mod 2^width
                BigInteger uUnMod
                    = r0.add(r1.multiply(tw)).mod(pow2w);
                
                byte uLocal;
                // if uUnMod >= 2^(width - 1)
                if (uUnMod.compareTo(pow2wMin1) >= 0)
                {
                    uLocal = (byte) uUnMod.subtract(pow2w).intValue();
                }
                else
                {
                    uLocal = (byte) uUnMod.intValue();
                }
                // uLocal is now in [-2^(width-1), 2^(width-1)-1]

                u[i] = uLocal;
                boolean s = true;
                if (uLocal < 0)
                {
                    s = false;
                    uLocal = (byte)-uLocal;
                }
                // uLocal is now >= 0

                if (s)
                {
                    r0 = r0.subtract(alpha[uLocal].u);
                    r1 = r1.subtract(alpha[uLocal].v);
                }
                else
                {
                    r0 = r0.add(alpha[uLocal].u);
                    r1 = r1.add(alpha[uLocal].v);
                }
            }
            else
            {
                u[i] = 0;
            }

            BigInteger t = r0;

            if (mu == 1)
            {
                r0 = r1.add(r0.shiftRight(1));
            }
            else
            {
                // mu == -1
                r0 = r1.subtract(r0.shiftRight(1));
            }
            r1 = t.shiftRight(1).negate();
            i++;
        }
        return u;
    }

    /**
     * Does the precomputation for WTNAF multiplication.
     * @param p The ECPoint for which to do the precomputation.
     * @param a The parameter a of the elliptic curve.
     * @return The precomputation array for p. 
     */
    public static ECPoint.F2m[] getPreComp(ECPoint.F2m p, byte a)
    {
        ECPoint.F2m[] pu;
        pu = new ECPoint.F2m[16];
        pu[1] = p;
        byte[][] alphaTnaf;
        if (a == 0)
        {
            alphaTnaf = Tnaf.alpha0Tnaf;
        }
        else
        {
            // a == 1
            alphaTnaf = Tnaf.alpha1Tnaf;
        }

        int precompLen = alphaTnaf.length;
        for (int i = 3; i < precompLen; i = i + 2)
        {
            pu[i] = Tnaf.multiplyFromTnaf(p, alphaTnaf[i]);
        }
        
        return pu;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy