Beispiel #1
0
        internal static void get_seed(HashFunctions hs, byte[] seed, int seedOff, byte[] sk, Tree.leafaddr a)
        {
            byte[] buffer = new byte[SPHINCS256Config.SEED_BYTES + 8];
            ulong  t;
            int    i;

            for (i = 0; i < SPHINCS256Config.SEED_BYTES; i++)
            {
                buffer[i] = sk[i];
            }

            //4 bits to encode level
            t = (uint)a.level;
            //55 bits to encode subtree
            t |= a.subtree << 4;
            //5 bits to encode leaf
            t |= a.subleaf << 59;

            Pack.UInt64_To_LE(t, buffer, SPHINCS256Config.SEED_BYTES);

            hs.varlen_hash(seed, seedOff, buffer, buffer.Length);
        }
Beispiel #2
0
        internal static void l_tree(HashFunctions hs, byte[] leaf, int leafOff, byte[] wots_pk, int pkOff, byte[] masks, int masksOff)
        {
            uint l = (uint)Wots.WOTS_L;
            int  i, j = 0;

            for (i = 0; i < Wots.WOTS_LOG_L; i++)
            {
                for (j = 0; j < (l >> 1); j++)
                {
                    hs.hash_2n_n_mask(wots_pk, pkOff + j * SPHINCS256Config.HASH_BYTES, wots_pk, pkOff + j * 2 * SPHINCS256Config.HASH_BYTES, masks, masksOff + i * 2 * SPHINCS256Config.HASH_BYTES);
                }

                if ((l & 1) != 0)
                {
                    Array.Copy(wots_pk, pkOff + (l - 1) * SPHINCS256Config.HASH_BYTES, wots_pk, pkOff + (l >> 1) * SPHINCS256Config.HASH_BYTES, SPHINCS256Config.HASH_BYTES);
                    l = (l >> 1) + 1;
                }
                else
                {
                    l = (l >> 1);
                }
            }
            Array.Copy(wots_pk, pkOff, leaf, leafOff, SPHINCS256Config.HASH_BYTES);
        }
Beispiel #3
0
        bool verify(HashFunctions hs, byte[] m, byte[] sm, byte[] pk)
        {
            int  i;
            int  smlen   = sm.Length;
            long leafidx = 0;

            byte[] wots_pk = new byte[Wots.WOTS_L * SPHINCS256Config.HASH_BYTES];
            byte[] pkhash  = new byte[SPHINCS256Config.HASH_BYTES];
            byte[] root    = new byte[SPHINCS256Config.HASH_BYTES];
            byte[] sig     = new byte[CRYPTO_BYTES];
            int    sigp;

            byte[] tpk = new byte[SPHINCS256Config.CRYPTO_PUBLICKEYBYTES];

            if (smlen != CRYPTO_BYTES)
            {
                throw new ArgumentException("signature wrong size");
            }

            byte[] m_h = new byte[SPHINCS256Config.MSGHASH_BYTES];

            for (i = 0; i < SPHINCS256Config.CRYPTO_PUBLICKEYBYTES; i++)
            {
                tpk[i] = pk[i];
            }

            // construct message hash
            {
                byte[] R = new byte[SPHINCS256Config.MESSAGE_HASH_SEED_BYTES];

                for (i = 0; i < SPHINCS256Config.MESSAGE_HASH_SEED_BYTES; i++)
                {
                    R[i] = sm[i];
                }

                Array.Copy(sm, 0, sig, 0, CRYPTO_BYTES);

                IDigest mHash = hs.getMessageHash();

                // input R
                mHash.BlockUpdate(R, 0, SPHINCS256Config.MESSAGE_HASH_SEED_BYTES);

                // input pub key
                mHash.BlockUpdate(tpk, 0, SPHINCS256Config.CRYPTO_PUBLICKEYBYTES);

                // input message
                mHash.BlockUpdate(m, 0, m.Length);

                mHash.DoFinal(m_h, 0);
            }

            sigp = 0;

            sigp  += SPHINCS256Config.MESSAGE_HASH_SEED_BYTES;
            smlen -= SPHINCS256Config.MESSAGE_HASH_SEED_BYTES;


            for (i = 0; i < (SPHINCS256Config.TOTALTREE_HEIGHT + 7) / 8; i++)
            {
                leafidx ^= ((long)(sig[sigp + i] & 0xff) << (8 * i));
            }


            Horst.horst_verify(hs, root, sig, sigp + (SPHINCS256Config.TOTALTREE_HEIGHT + 7) / 8,
                               tpk, m_h);

            sigp  += (SPHINCS256Config.TOTALTREE_HEIGHT + 7) / 8;
            smlen -= (SPHINCS256Config.TOTALTREE_HEIGHT + 7) / 8;

            sigp  += Horst.HORST_SIGBYTES;
            smlen -= Horst.HORST_SIGBYTES;

            Wots w = new Wots();

            for (i = 0; i < SPHINCS256Config.N_LEVELS; i++)
            {
                w.wots_verify(hs, wots_pk, sig, sigp, root, tpk);

                sigp  += Wots.WOTS_SIGBYTES;
                smlen -= Wots.WOTS_SIGBYTES;

                Tree.l_tree(hs, pkhash, 0, wots_pk, 0, tpk, 0);
                validate_authpath(hs, root, pkhash, (uint)(leafidx & 0x1f), sig, sigp, tpk, SPHINCS256Config.SUBTREE_HEIGHT);
                leafidx >>= 5;

                sigp  += SPHINCS256Config.SUBTREE_HEIGHT * SPHINCS256Config.HASH_BYTES;
                smlen -= SPHINCS256Config.SUBTREE_HEIGHT * SPHINCS256Config.HASH_BYTES;
            }

            bool verified = true;

            for (i = 0; i < SPHINCS256Config.HASH_BYTES; i++)
            {
                if (root[i] != tpk[i + Horst.N_MASKS * SPHINCS256Config.HASH_BYTES])
                {
                    verified = false;
                }
            }

            return(verified);
        }
Beispiel #4
0
        byte[] crypto_sign(HashFunctions hs, byte[] m, byte[] sk)
        {
            byte[] sm = new byte[CRYPTO_BYTES];
            int    i;
            ulong  leafidx;

            byte[]  R   = new byte[SPHINCS256Config.MESSAGE_HASH_SEED_BYTES];
            byte[]  m_h = new byte[SPHINCS256Config.MSGHASH_BYTES];
            ulong[] rnd = new ulong[8];

            byte[] root  = new byte[SPHINCS256Config.HASH_BYTES];
            byte[] seed  = new byte[SPHINCS256Config.SEED_BYTES];
            byte[] masks = new byte[Horst.N_MASKS * SPHINCS256Config.HASH_BYTES];
            int    pk;

            byte[] tsk = new byte[SPHINCS256Config.CRYPTO_SECRETKEYBYTES];

            for (i = 0; i < SPHINCS256Config.CRYPTO_SECRETKEYBYTES; i++)
            {
                tsk[i] = sk[i];
            }

            // create leafidx deterministically
            {
                // shift scratch upwards so we can reuse msg later
                int scratch = CRYPTO_BYTES - SPHINCS256Config.SK_RAND_SEED_BYTES;

                // Copy secret random seed to scratch
                Array.Copy(tsk, SPHINCS256Config.CRYPTO_SECRETKEYBYTES - SPHINCS256Config.SK_RAND_SEED_BYTES, sm, scratch, SPHINCS256Config.SK_RAND_SEED_BYTES);

                IDigest d    = hs.getMessageHash();
                byte[]  bRnd = new byte[d.GetDigestSize()];

                d.BlockUpdate(sm, scratch, SPHINCS256Config.SK_RAND_SEED_BYTES);

                d.BlockUpdate(m, 0, m.Length);

                d.DoFinal(bRnd, 0);
                // wipe sk
                zerobytes(sm, scratch, SPHINCS256Config.SK_RAND_SEED_BYTES);

                for (int j = 0; j != rnd.Length; j++)
                {
                    rnd[j] = Pack.LE_To_UInt64(bRnd, j * 8);
                }
                leafidx = rnd[0] & 0xfffffffffffffffUL;

                Array.Copy(bRnd, 16, R, 0, SPHINCS256Config.MESSAGE_HASH_SEED_BYTES);

                // prepare msg_hash
                scratch = CRYPTO_BYTES - SPHINCS256Config.MESSAGE_HASH_SEED_BYTES - SPHINCS256Config.CRYPTO_PUBLICKEYBYTES;

                // cpy R
                Array.Copy(R, 0, sm, scratch, SPHINCS256Config.MESSAGE_HASH_SEED_BYTES);

                // construct and cpy pk
                Tree.leafaddr b = new Tree.leafaddr();
                b.level   = SPHINCS256Config.N_LEVELS - 1;
                b.subtree = 0;
                b.subleaf = 0;

                pk = scratch + SPHINCS256Config.MESSAGE_HASH_SEED_BYTES;

                Array.Copy(tsk, SPHINCS256Config.SEED_BYTES, sm, pk, Horst.N_MASKS * SPHINCS256Config.HASH_BYTES);

                Tree.treehash(hs, sm, pk + (Horst.N_MASKS * SPHINCS256Config.HASH_BYTES), SPHINCS256Config.SUBTREE_HEIGHT, tsk, b, sm, pk);

                d = hs.getMessageHash();

                d.BlockUpdate(sm, scratch, SPHINCS256Config.MESSAGE_HASH_SEED_BYTES + SPHINCS256Config.CRYPTO_PUBLICKEYBYTES);
                d.BlockUpdate(m, 0, m.Length);
                d.DoFinal(m_h, 0);
            }

            Tree.leafaddr a = new Tree.leafaddr();

            a.level   = SPHINCS256Config.N_LEVELS; // Use unique value $d$ for HORST address.
            a.subleaf = (leafidx & (1UL << SPHINCS256Config.SUBTREE_HEIGHT) - 1);
            a.subtree = (leafidx >> SPHINCS256Config.SUBTREE_HEIGHT);

            int smlen = 0;

            for (i = 0; i < SPHINCS256Config.MESSAGE_HASH_SEED_BYTES; i++)
            {
                sm[i] = R[i];
            }

            int smOff = SPHINCS256Config.MESSAGE_HASH_SEED_BYTES;

            smlen += SPHINCS256Config.MESSAGE_HASH_SEED_BYTES;

            Array.Copy(tsk, SPHINCS256Config.SEED_BYTES, masks, 0, Horst.N_MASKS * SPHINCS256Config.HASH_BYTES);
            for (i = 0; i < (SPHINCS256Config.TOTALTREE_HEIGHT + 7) / 8; i++)
            {
                sm[smOff + i] = (byte)((leafidx >> 8 * i) & 0xff);
            }

            smOff += (SPHINCS256Config.TOTALTREE_HEIGHT + 7) / 8;
            smlen += (SPHINCS256Config.TOTALTREE_HEIGHT + 7) / 8;

            Seed.get_seed(hs, seed, 0, tsk, a);

            int horst_sigbytes = Horst.horst_sign(hs, sm, smOff, root, seed, masks, m_h);

            smOff += horst_sigbytes;
            smlen += horst_sigbytes;

            Wots w = new Wots();

            for (i = 0; i < SPHINCS256Config.N_LEVELS; i++)
            {
                a.level = i;

                Seed.get_seed(hs, seed, 0, tsk, a); //XXX: Don't use the same address as for horst_sign here!

                w.wots_sign(hs, sm, smOff, root, seed, masks);

                smOff += Wots.WOTS_SIGBYTES;
                smlen += Wots.WOTS_SIGBYTES;

                compute_authpath_wots(hs, root, sm, smOff, a, tsk, masks, SPHINCS256Config.SUBTREE_HEIGHT);
                smOff += SPHINCS256Config.SUBTREE_HEIGHT * SPHINCS256Config.HASH_BYTES;
                smlen += SPHINCS256Config.SUBTREE_HEIGHT * SPHINCS256Config.HASH_BYTES;

                a.subleaf   = (a.subtree & ((1UL << SPHINCS256Config.SUBTREE_HEIGHT) - 1));
                a.subtree >>= SPHINCS256Config.SUBTREE_HEIGHT;
            }

            zerobytes(tsk, 0, SPHINCS256Config.CRYPTO_SECRETKEYBYTES);

            return(sm);
        }
Beispiel #5
0
        internal static int horst_verify(HashFunctions hs, byte[] pk, byte[] sig, int sigOff, byte[] masks, byte[] m_hash)
        {
            byte[] buffer = new byte[32 * HASH_BYTES];

            uint idx;
            int  i, j, k;

            int sigOffset = sigOff + 64 * HASH_BYTES;

            for (i = 0; i < HORST_K; i++)
            {
                idx = (uint)((m_hash[2 * i] & 0xff) + ((m_hash[2 * i + 1] & 0xff) << 8));

                if ((idx & 1) == 0)
                {
                    hs.hash_n_n(buffer, 0, sig, sigOffset);
                    for (k = 0; k < HASH_BYTES; k++)
                    {
                        buffer[HASH_BYTES + k] = sig[sigOffset + HORST_SKBYTES + k];
                    }
                }
                else
                {
                    hs.hash_n_n(buffer, HASH_BYTES, sig, sigOffset);
                    for (k = 0; k < HASH_BYTES; k++)
                    {
                        buffer[k] = sig[sigOffset + HORST_SKBYTES + k];
                    }
                }
                sigOffset += HORST_SKBYTES + HASH_BYTES;

                for (j = 1; j < HORST_LOGT - 6; j++)
                {
                    idx = idx >> 1; // parent node

                    if ((idx & 1) == 0)
                    {
                        hs.hash_2n_n_mask(buffer, 0, buffer, 0, masks, 2 * (j - 1) * HASH_BYTES);
                        for (k = 0; k < HASH_BYTES; k++)
                        {
                            buffer[HASH_BYTES + k] = sig[sigOffset + k];
                        }
                    }
                    else
                    {
                        hs.hash_2n_n_mask(buffer, HASH_BYTES, buffer, 0, masks, 2 * (j - 1) * HASH_BYTES);
                        for (k = 0; k < HASH_BYTES; k++)
                        {
                            buffer[k] = sig[sigOffset + k];
                        }
                    }
                    sigOffset += HASH_BYTES;
                }

                idx = idx >> 1; // parent node
                hs.hash_2n_n_mask(buffer, 0, buffer, 0, masks, 2 * (HORST_LOGT - 7) * HASH_BYTES);

                for (k = 0; k < HASH_BYTES; k++)
                {
                    if (sig[sigOff + idx * HASH_BYTES + k] != buffer[k])
                    {
                        for (k = 0; k < HASH_BYTES; k++)
                        {
                            pk[k] = 0;
                        }
                        return(-1);
                    }
                }
            }

            // Compute root from level10
            for (j = 0; j < 32; j++)
            {
                hs.hash_2n_n_mask(buffer, j * HASH_BYTES, sig, sigOff + 2 * j * HASH_BYTES, masks, 2 * (HORST_LOGT - 6) * HASH_BYTES);
            }
            // Hash from level 11 to 12
            for (j = 0; j < 16; j++)
            {
                hs.hash_2n_n_mask(buffer, j * HASH_BYTES, buffer, 2 * j * HASH_BYTES, masks, 2 * (HORST_LOGT - 5) * HASH_BYTES);
            }
            // Hash from level 12 to 13
            for (j = 0; j < 8; j++)
            {
                hs.hash_2n_n_mask(buffer, j * HASH_BYTES, buffer, 2 * j * HASH_BYTES, masks, 2 * (HORST_LOGT - 4) * HASH_BYTES);
            }
            // Hash from level 13 to 14
            for (j = 0; j < 4; j++)
            {
                hs.hash_2n_n_mask(buffer, j * HASH_BYTES, buffer, 2 * j * HASH_BYTES, masks, 2 * (HORST_LOGT - 3) * HASH_BYTES);
            }
            // Hash from level 14 to 15
            for (j = 0; j < 2; j++)
            {
                hs.hash_2n_n_mask(buffer, j * HASH_BYTES, buffer, 2 * j * HASH_BYTES, masks, 2 * (HORST_LOGT - 2) * HASH_BYTES);
            }
            // Hash from level 15 to 16

            hs.hash_2n_n_mask(pk, 0, buffer, 0, masks, 2 * (HORST_LOGT - 1) * HASH_BYTES);

            return(0);
        }
Beispiel #6
0
        internal static int horst_sign(HashFunctions hs,
                                       byte[] sig, int sigOff, byte[] pk,
                                       byte[] seed,
                                       byte[] masks,
                                       byte[] m_hash)
        {
            byte[] sk = new byte[HORST_T * HORST_SKBYTES];
            uint   idx;
            int    i, j, k;
            int    sigpos = sigOff;

            byte[] tree = new byte[(2 * HORST_T - 1) * HASH_BYTES]; /* replace by something more memory-efficient? */

            expand_seed(sk, seed);

            // Build the whole tree and save it

            // Generate pk leaves
            for (i = 0; i < HORST_T; i++)
            {
                hs.hash_n_n(tree, (HORST_T - 1 + i) * HASH_BYTES, sk, i * HORST_SKBYTES);
            }

            long offset_in, offset_out;

            for (i = 0; i < HORST_LOGT; i++)
            {
                offset_in  = (1 << (HORST_LOGT - i)) - 1;
                offset_out = (1 << (HORST_LOGT - i - 1)) - 1;
                for (j = 0; j < (1 << (HORST_LOGT - i - 1)); j++)
                {
                    hs.hash_2n_n_mask(tree, (int)((offset_out + j) * HASH_BYTES), tree, (int)((offset_in + 2 * j) * HASH_BYTES), masks, 2 * i * HASH_BYTES);
                }
            }

            // First write 64 hashes from level 10 to the signature
            for (j = 63 * HASH_BYTES; j < 127 * HASH_BYTES; j++)
            {
                sig[sigpos++] = tree[j];
            }

            // Signature consists of HORST_K parts; each part of secret key and HORST_LOGT-4 auth-path hashes
            for (i = 0; i < HORST_K; i++)
            {
                idx = (uint)((m_hash[2 * i] & 0xff) + ((m_hash[2 * i + 1] & 0xff) << 8));

                for (k = 0; k < HORST_SKBYTES; k++)
                {
                    sig[sigpos++] = sk[idx * HORST_SKBYTES + k];
                }

                idx += (uint)(HORST_T - 1);
                for (j = 0; j < HORST_LOGT - 6; j++)
                {
                    idx = ((idx & 1) != 0) ? idx + 1 : idx - 1; // neighbor node
                    for (k = 0; k < HASH_BYTES; k++)
                    {
                        sig[sigpos++] = tree[idx * HASH_BYTES + k];
                    }
                    idx = (idx - 1) / 2; // parent node
                }
            }

            for (i = 0; i < HASH_BYTES; i++)
            {
                pk[i] = tree[i];
            }

            return(HORST_SIGBYTES);
        }