#include "config.h"
#if !HAVE_CRYPTOPP
#warning Compiling built-in cryptography support.
#warning If xMule behaves erratically, consider installing libcrypto++ and recompiling xMule.
	
/*
 Compilation Copyright (c) 1995-2003 by Wei Dai.  All rights reserved.
 This copyright applies only to this software distribution package
 as a compilation, and does not imply a copyright on any particular
 file in the package.
 The following files are copyrighted by their respective original authors,
 and their use is subject to additional licenses included in these files.
 mars.cpp - Copyright 1998 Brian Gladman.
 All other files in this compilation are placed in the public domain by
 Wei Dai and other contributors.
 I would like to thank the following authors for placing their works into
 the public domain:
 Joan Daemen - 3way.cpp
 Leonard Janke - cast.cpp, seal.cpp
 Steve Reid - cast.cpp
 Phil Karn - des.cpp
 Michael Paul Johnson - diamond.cpp
 Andrew M. Kuchling - md2.cpp, md4.cpp
 Colin Plumb - md5.cpp, md5mac.cpp
 Seal Woods - rc6.cpp
 Chris Morgan - rijndael.cpp
 Paulo Baretto - rijndael.cpp, skipjack.cpp, square.cpp
 Richard De Moliner - safer.cpp
 Matthew Skala - twofish.cpp
 Permission to use, copy, modify, and distribute this compilation for
 any purpose, including commercial applications, is hereby granted
 without fee, subject to the following restrictions:
 1. Any copy or modification of this compilation in any form, except
 in object code form as part of an application software, must include
 the above copyright notice and this license.
 2. Users of this software agree that any modification or extension
 they provide to Wei Dai will be considered public domain and not
 copyrighted unless it includes an explicit copyright notice.
 3. Wei Dai makes no warranty or representation that the operation of the
 software in this compilation will be error-free, and Wei Dai is under no
 obligation to provide any services, by way of maintenance, update, or
 otherwise.  THE SOFTWARE AND ANY DOCUMENTATION ARE PROVIDED "AS IS"
 WITHOUT EXPRESS OR IMPLIED WARRANTY INCLUDING, BUT NOT LIMITED TO,
 THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 PURPOSE. IN NO EVENT WILL WEI DAI OR ANY OTHER CONTRIBUTOR BE LIABLE FOR
 DIRECT, INCIDENTAL OR CONSEQUENTIAL DAMAGES, EVEN IF
 ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
 4. Users will not use Wei Dai or any other contributor's name in any
 publicity or advertising, without prior written consent in each case.
 5. Export of this software from the United States may require a
 specific license from the United States Government.  It is the
 responsibility of any person or organization contemplating export
 to obtain such a license before exporting.
 6. Certain parts of this software may be protected by patents.  It
 is the users' responsibility to obtain the appropriate
 licenses before using those parts.
 If this compilation is used in object code form in an application
 software, acknowledgement of the author is not required but would be
 appreciated. The contribution of any useful modifications or extensions
 to Wei Dai is not required but would also be appreciated.
    */

 /*
 only the for xmule needed parts taken from cryptopp in 2004 by upload2010
    */

#include <errno.h>
#include <fcntl.h>
#include <iomanip>
#include <iostream>
#include <math.h>
#include <memory>
#include <time.h>
#include <unistd.h>

#include "CryptoXMpp.h"

// algebra.cpp - written and placed in the public domain by Wei Dai

namespace CryptoXMpp
{
    template <class T > const T & AbstractGroup <T >::Double(const Element & a) const
    {
        return Add(a, a);
    }
    template <class T > const T & AbstractGroup <T >::Subtract(const Element & a, const Element & b) const
    {
        // make copy of a in case Inverse() overwrites it
        Element a1(a);
        return Add(a1, Inverse(b));
    }
    template <class T > T & AbstractGroup <T >::Accumulate(Element & a, const Element & b) const
    {
        return a = Add(a, b);
    }
    template <class T > T & AbstractGroup <T >::Reduce(Element & a, const Element & b) const
    {
        return a = Subtract(a, b);
    }
    template <class T > const T & AbstractRing <T >::Square(const Element & a) const
    {
        return Multiply(a, a);
    }
    template <class T > const T & AbstractRing <T >::Divide(const Element & a, const Element & b) const
    {
        // make copy of a in case MultiplicativeInverse() overwrites it
        Element a1(a);
        return Multiply(a1, MultiplicativeInverse(b));
    }
    template <class T > const T & AbstractEuclideanDomain <T >::Mod(const Element & a, const Element & b) const
    {
        Element q;
        DivisionAlgorithm(result, q, a, b);
        return result;
    }
    template <class T > const T & AbstractEuclideanDomain <T >::Gcd(const Element & a, const Element & b) const
    {
        Element g[3] =
        {
            b, a
                };
        unsigned int i0 = 0, i1 = 1, i2 = 2;
        while (!Equal(g[i1], this->Identity()))
        {
            g[i2] = Mod(g[i0], g[i1]);
            unsigned int t = i0;
            i0 = i1;
            i1 = i2;
            i2 = t;
        }
        return result = g[i0];
    }
    template <class T > const typename QuotientRing <T >::Element & QuotientRing <T >::MultiplicativeInverse(const Element & a) const
    {
        Element g[3] =
        {
            m_modulus, a
                };
        Element v[3] =
        {
            m_domain.Identity(), m_domain.MultiplicativeIdentity()
                };
        Element y;
        unsigned int i0 = 0, i1 = 1, i2 = 2;
        while (!Equal(g[i1], Identity()))
        {
            // y = g[i0] / g[i1];
            // g[i2] = g[i0] % g[i1];
            m_domain.DivisionAlgorithm(g[i2], y, g[i0], g[i1]);
            // v[i2] = v[i0] - (v[i1] * y);
            v[i2] = m_domain.Subtract(v[i0], m_domain.Multiply(v[i1], y));
            unsigned int t = i0;
            i0 = i1;
            i1 = i2;
            i2 = t;
        }
        return m_domain.IsUnit(g[i0]) ? m_domain.Divide(v[i0], g[i0]): m_domain.Identity();
    }
    template <class T > T AbstractGroup <T >::ScalarMultiply(const Element & base, const Integer & exponent) const
    {
        Element result;
        SimultaneousMultiply( & result, base, & exponent, 1);
        return result;
    }
    template <class T > T AbstractGroup <T >::CascadeScalarMultiply(const Element & x, const Integer & e1, const Element & y, const Integer & e2) const
    {
        const unsigned expLen = STDMAX(e1.BitCount(), e2.BitCount());
        if (expLen == 0)
        return Identity();
        const unsigned w = (expLen <= 46 ? 1: (expLen <= 260 ? 2: 3));
        const unsigned tableSize = 1 <<w;
        std::vector <Element > powerTable(tableSize << w);
        powerTable[1] = x;
        powerTable[tableSize] = y;
        if (w == 1)
        powerTable[3] = Add(x, y);
        else
        {
            powerTable[2] = Double(x);
            powerTable[2 * tableSize] = Double(y);
            unsigned i, j;
            for (i = 3 ; i < tableSize ; i += 2)
            powerTable[i] = Add(powerTable[i - 2], powerTable[2]);
            for (i = 1 ; i < tableSize ; i += 2)
            for (j = i + tableSize ; j < (tableSize << w) ; j += tableSize)
            powerTable[j] = Add(powerTable[j - tableSize], y);
            for (i = 3 * tableSize ; i < (tableSize << w) ; i += 2 * tableSize)
            powerTable[i] = Add(powerTable[i - 2 * tableSize], powerTable[2 * tableSize]);
            for (i = tableSize ; i < (tableSize << w) ; i += 2 * tableSize)
            for (j = i + 2 ; j < i + tableSize ; j += 2)
            powerTable[j] = Add(powerTable[j - 1], x);
        }
        Element result;
        unsigned power1 = 0, power2 = 0, prevPosition = expLen - 1;
        bool firstTime = true;
        for (int i = expLen - 1 ; i >= 0 ; i--)
        {
            power1 = 2 * power1 + e1.GetBit(i);
            power2 = 2 * power2 + e2.GetBit(i);
            if (i == 0 || 2 * power1 >= tableSize || 2 * power2 >= tableSize)
            {
                unsigned squaresBefore = prevPosition - i;
                unsigned squaresAfter = 0;
                prevPosition = i;
                while ((power1 || power2) && power1% 2 == 0 && power2% 2 == 0)
                {
                    power1 /= 2;
                    power2 /= 2;
                    squaresBefore--;
                    squaresAfter++;
                }
                if (firstTime)
                {
                    result = powerTable[ (power2 << w) + power1];
                    firstTime = false;
                }
                else
                {
                    while (squaresBefore--)
                    result = Double(result);
                    if (power1 || power2)
                    Accumulate(result, powerTable[ (power2 << w) + power1]);
                }
                while (squaresAfter--)
                result = Double(result);
                power1 = power2 = 0;
            }
        }
        return result;
    }
    template <class Element, class Iterator > Element GeneralCascadeMultiplication(const AbstractGroup < Element > & group, Iterator begin, Iterator end)
    {
        if (end - begin == 1)
        return group.ScalarMultiply(begin->base, begin->exponent);
        else if(end - begin == 2)
        return group.CascadeScalarMultiply(begin->base, begin->exponent, (begin + 1)->base, (begin + 1)->exponent);
        else
        {
            Integer q, t;
            Iterator last = end;
            --last;
            std::make_heap(begin, end);
            std::pop_heap(begin, end);
            while (! !begin->exponent)
            {
                // last->exponent is largest exponent, begin->exponent is next largest
                t = last->exponent;
                Integer::Divide(last->exponent, q, t, begin->exponent);
                if (q == Integer::One())
                group.Accumulate(begin->base, last->base);
                // avoid overhead of ScalarMultiply()
                else
                group.Accumulate(begin->base, group.ScalarMultiply(last->base, q));
                std::push_heap(begin, end);
                std::pop_heap(begin, end);
            }
            return group.ScalarMultiply(last->base, last->exponent);
        }
    }
    struct WindowSlider
    {
        WindowSlider(const Integer & exp, bool fastNegate, unsigned int windowSizeIn = 0)
        : exp(exp), windowModulus(Integer::One()), windowSize(windowSizeIn), windowBegin(0), fastNegate(fastNegate), firstTime(true), finished(false)
        {
            if (windowSize == 0)
            {
                unsigned int expLen = exp.BitCount();
                windowSize = expLen <= 17 ? 1: (expLen <= 24 ? 2: (expLen <= 70 ? 3: (expLen <= 197 ? 4: (expLen <= 539 ? 5: (expLen <= 1434 ? 6: 7)))));
            }
            windowModulus <<= windowSize;
        }
        void FindNextWindow()
        {
            unsigned int expLen = exp.WordCount() * WORD_BITS;
            unsigned int skipCount = firstTime ? 0: windowSize;
            firstTime = false;
            while (!exp.GetBit(skipCount))
            {
                if (skipCount >= expLen)
                {
                    finished = true;
                    return;
                }
                skipCount++;
            }
            exp >>= skipCount;
            windowBegin += skipCount;
            expWindow = exp % (1 << windowSize);
            if (fastNegate && exp.GetBit(windowSize))
            {
                negateNext = true;
                expWindow = (1 << windowSize) - expWindow;
                exp += windowModulus;
            }
            else
            negateNext = false;
        }
        Integer exp, windowModulus;
        unsigned int windowSize, windowBegin, expWindow;
        bool fastNegate, negateNext, firstTime, finished;
        };
    template <class T >
    void AbstractGroup <T >::SimultaneousMultiply(T * results, const T & base, const Integer * expBegin, unsigned int expCount) const
    {
        std::vector <std::vector <Element > > buckets(expCount);
        std::vector <WindowSlider > exponents;
        exponents.reserve(expCount);
        unsigned int i;
        for (i = 0 ; i < expCount ; i++)
        {
            assert(expBegin->NotNegative());
            exponents.push_back(WindowSlider( * expBegin++, InversionIsFast(), 0));
            exponents[i].FindNextWindow();
            buckets[i].resize(1 << (exponents[i].windowSize - 1), Identity());
        }
        unsigned int expBitPosition = 0;
        Element g = base;
        bool notDone = true;
        while (notDone)
        {
            notDone = false;
            for (i = 0 ; i < expCount ; i++)
            {
                if (!exponents[i].finished && expBitPosition == exponents[i].windowBegin)
                {
                    Element & bucket = buckets[i][exponents[i].expWindow/ 2];
                    if (exponents[i].negateNext)
                    Accumulate(bucket, Inverse(g));
                    else
                    Accumulate(bucket, g);
                    exponents[i].FindNextWindow();
                }
                notDone = notDone || !exponents[i].finished;
            }
            if (notDone)
            {
                g = Double(g);
                expBitPosition++;
            }
        }
        for (i = 0 ; i < expCount ; i++)
        {
            Element & r = * results++;
            r = buckets[i][buckets[i].size() - 1];
            if (buckets[i].size() > 1)
            {
                for (int j = buckets[i].size() - 2 ; j >= 1 ; j--)
                {
                    Accumulate(buckets[i][j], buckets[i][j + 1]);
                    Accumulate(r, buckets[i][j]);
                }
                Accumulate(buckets[i][0], buckets[i][1]);
                r = Add(Double(r), buckets[i][0]);
            }
        }
    }
    template <class T > T AbstractRing <T >::Exponentiate(const Element & base, const Integer & exponent) const
    {
        Element result;
        SimultaneousExponentiate( & result, base, & exponent, 1);
        return result;
    }
    template <class T > T AbstractRing <T >::CascadeExponentiate(const Element & x, const Integer & e1, const Element & y, const Integer & e2) const
    {
        return MultiplicativeGroup() .AbstractGroup <T >::CascadeScalarMultiply(x, e1, y, e2);
    }
    template <class Element, class Iterator > Element GeneralCascadeExponentiation(const AbstractRing < Element > & ring, Iterator begin, Iterator end)
    {
        return GeneralCascadeMultiplication <Element > (ring.MultiplicativeGroup(), begin, end);
    }
    template <class T >
    void AbstractRing <T >::SimultaneousExponentiate(T * results, const T & base, const Integer * exponents, unsigned int expCount) const
    {
        MultiplicativeGroup() .AbstractGroup <T >::SimultaneousMultiply(results, base, exponents, expCount);
    }
    //faz:algparam.cpp - written and placed in the public domain by Wei Dai
    bool( * AssignIntToInteger)(const std::type_info & valueType, void * pInteger, const void * pInt) = NULL;
    word32 Spbox[8][64];
    //faz: asn.cpp - written and placed in the public domain by Wei Dai
    using namespace std;
    /// DER Length
    unsigned int DERLengthEncode(BufferedTransformation & bt, unsigned int length)
    {
        unsigned int i = 0;
        if (length <= 0x7f)
        {
            bt.Put(byte(length));
            i++;
        }
        else
        {
            bt.Put(byte(BytePrecision(length) | 0x80));
            i++;
            for (int j = BytePrecision(length) ; j ;--j)
            {
                bt.Put(byte(length >> (j - 1) * 8));
                i++;
            }
        }
        return i;
    }
    bool BERLengthDecode(BufferedTransformation & bt, unsigned int & length, bool & definiteLength)
    {
        byte b;
        if (!bt.Get(b))
        return false;
        if (! (b & 0x80))
        {
            definiteLength = true;
            length = b;
        }
        else
        {
            unsigned int lengthBytes = b & 0x7f;
            if (lengthBytes == 0)
            {
                definiteLength = false;
                return true;
            }
            definiteLength = true;
            length = 0;
            while (lengthBytes--)
            {
                if (length >> (8 * (sizeof(length) - 1)))
                BERDecodeError();
                // length about to overflow
                if (!bt.Get(b))
                return false;
                length = (length << 8) | b;
            }
        }
        return true;
    }
    bool BERLengthDecode(BufferedTransformation & bt, unsigned int & length)
    {
        bool definiteLength;
        if (!BERLengthDecode(bt, length, definiteLength))
        BERDecodeError();
        return definiteLength;
    }
    void DEREncodeNull(BufferedTransformation & out)
    {
        out.Put(TAG_NULL);
        out.Put(0);
    }
    void BERDecodeNull(BufferedTransformation & in)
    {
        byte b;
        if (!in.Get(b) || b != TAG_NULL)
        BERDecodeError();
        unsigned int length;
        if (!BERLengthDecode(in, length) || length != 0)
        BERDecodeError();
    }
    /// ASN Strings
    unsigned int DEREncodeOctetString(BufferedTransformation & bt, const byte * str, unsigned int strLen)
    {
        bt.Put(OCTET_STRING);
        unsigned int lengthBytes = DERLengthEncode(bt, strLen);
        bt.Put(str, strLen);
        return 1 + lengthBytes + strLen;
    }
    unsigned int DEREncodeOctetString(BufferedTransformation & bt, const SecByteBlock & str)
    {
        return DEREncodeOctetString(bt, str.begin(), str.size());
    }
    void OID::EncodeValue(BufferedTransformation & bt, unsigned long v)
    {
        for (unsigned int i = RoundUpToMultipleOf(STDMAX(7U, BitPrecision(v)), 7U) - 7 ; i != 0 ; i -= 7)
        bt.Put((byte)(0x80 | ((v >> i) & 0x7f)));
        bt.Put((byte)(v & 0x7f));
    }
    unsigned int OID::DecodeValue(BufferedTransformation & bt, unsigned long & v)
    {
        byte b;
        unsigned int i = 0;
        v = 0;
        while (true)
        {
            if (!bt.Get(b))
            BERDecodeError();
            i++;
            v <<= 7;
            v += b & 0x7f;
            if (! (b & 0x80))
            return i;
        }
    }
    void OID::DEREncode(BufferedTransformation & bt) const
    {
        assert(m_values.size() >= 2);
        ByteQueue temp;
        temp.Put(byte(m_values[0] * 40 + m_values[1]));
        for (unsigned int i = 2 ; i < m_values.size() ; i++)
        EncodeValue(temp, m_values[i]);
        bt.Put(OBJECT_IDENTIFIER);
        DERLengthEncode(bt, temp.CurrentSize());
        temp.TransferTo(bt);
    }
    void OID::BERDecode(BufferedTransformation & bt)
    {
        byte b;
        if (!bt.Get(b) || b != OBJECT_IDENTIFIER)
        BERDecodeError();
        unsigned int length;
        if (!BERLengthDecode(bt, length) || length < 1)
        BERDecodeError();
        if (!bt.Get(b))
        BERDecodeError();
        length--;
        m_values.resize(2);
        m_values[0] = b / 40;
        m_values[1] = b % 40;
        while (length > 0)
        {
            unsigned long v;
            unsigned int valueLen = DecodeValue(bt, v);
            if (valueLen > length)
            BERDecodeError();
            m_values.push_back(v);
            length -= valueLen;
        }
    }
    void OID::BERDecodeAndCheck(BufferedTransformation & bt) const
    {
        OID oid(bt);
        if ( * this != oid)
        BERDecodeError();
    }
    inline BufferedTransformation & EncodedObjectFilter::CurrentTarget()
    {
        if (m_flags & PUT_OBJECTS)
        return * AttachedTransformation();
        else
        return TheBitBucket();
    }
    void EncodedObjectFilter::Put(const byte * inString, unsigned int length)
    {
        if (m_nCurrentObject == m_nObjects)
        {
            AttachedTransformation()->Put(inString, length);
            return;
        }
        LazyPutter lazyPutter(m_queue, inString, length);
        while (m_queue.AnyRetrievable())
        {
            switch (m_state)
            {
            case IDENTIFIER:
                if (!m_queue.Get(m_id))
                return;
                m_queue.TransferTo(CurrentTarget(), 1);
                m_state = LENGTH;
                // fall through
            case LENGTH:
                {
                    byte b;
                    if (m_level > 0 && m_id == 0 && m_queue.Peek(b) && b == 0)
                    {
                        m_queue.TransferTo(CurrentTarget(), 1);
                        m_level--;
                        m_state = IDENTIFIER;
                        break;
                    }
                    ByteQueue::Walker walker(m_queue);
                    bool definiteLength;
                    if (!BERLengthDecode(walker, m_lengthRemaining, definiteLength))
                    return;
                    m_queue.TransferTo(CurrentTarget(), walker.GetCurrentPosition());
                    if (! ((m_id & CONSTRUCTED) || definiteLength))
                    BERDecodeError();
                    if (!definiteLength)
                    {
                        if (! (m_id & CONSTRUCTED))
                        BERDecodeError();
                        m_level++;
                        m_state = IDENTIFIER;
                        break;
                    }
                    m_state = BODY;
                    // fall through
                }
            case BODY:
                m_lengthRemaining -= m_queue.TransferTo(CurrentTarget(), m_lengthRemaining);
                if (m_lengthRemaining == 0)
                m_state = IDENTIFIER;
            default:
                break;
            }
            if (m_state == IDENTIFIER && m_level == 0)
            {
                // just finished processing a level 0 object
                ++m_nCurrentObject;
                if (m_flags & PUT_MESSANGE_END_AFTER_EACH_OBJECT)
                AttachedTransformation()->MessageEnd();
                if (m_nCurrentObject == m_nObjects)
                {
                    if (m_flags & PUT_MESSANGE_END_AFTER_ALL_OBJECTS)
                    AttachedTransformation()->MessageEnd();
                    if (m_flags & PUT_MESSANGE_SERIES_END_AFTER_ALL_OBJECTS)
                    AttachedTransformation()->MessageSeriesEnd();
                    m_queue.TransferAllTo( * AttachedTransformation());
                    return;
                }
            }
        }
    }
    BERGeneralDecoder::BERGeneralDecoder(BufferedTransformation & inQueue, byte asnTag)
    : m_inQueue(inQueue), m_finished(false)
    {
        byte b;
        if (!m_inQueue.Get(b) || b != asnTag)
        BERDecodeError();
        m_definiteLength = BERLengthDecode(m_inQueue, m_length);
    }
    BERGeneralDecoder::BERGeneralDecoder(BERGeneralDecoder & inQueue, byte asnTag)
    : m_inQueue(inQueue), m_finished(false)
    {
        byte b;
        if (!m_inQueue.Get(b) || b != asnTag)
        BERDecodeError();
        m_definiteLength = BERLengthDecode(m_inQueue, m_length);
        if (!m_definiteLength && ! (asnTag & CONSTRUCTED))
        BERDecodeError();
        // cannot be primitive have indefinite length
    }
    BERGeneralDecoder::~ BERGeneralDecoder()
    {
        // avoid throwing in constructor:
        try
        {
            if (!m_finished)
            MessageEnd();
        }
        catch(...)
        {
        }
    }
    bool BERGeneralDecoder::EndReached() const
    {
        if (m_definiteLength)
        return m_length == 0;
        else
        {
            // check end-of-content octets
            word16 i;
            return(m_inQueue.PeekWord16(i) == 2 && i == 0);
        }
    }
    byte BERGeneralDecoder::PeekByte() const
    {
        byte b;
        if (!Peek(b))
        BERDecodeError();
        return b;
    }
    void BERGeneralDecoder::CheckByte(byte check)
    {
        byte b;
        if (!Get(b) || b != check)
        BERDecodeError();
    }
    void BERGeneralDecoder::MessageEnd()
    {
        m_finished = true;
        if (m_definiteLength)
        {
            if (m_length != 0)
            BERDecodeError();
        }
        else
        {
            // remove end-of-content octets
            word16 i;
            if (m_inQueue.GetWord16(i) != 2 || i != 0)
            BERDecodeError();
        }
    }
    unsigned int BERGeneralDecoder::TransferTo2(BufferedTransformation & target, unsigned long & transferBytes, const std::string & channel, bool blocking)
    {
        if (m_definiteLength && transferBytes > m_length)
        transferBytes = m_length;
        unsigned int blockedBytes = m_inQueue.TransferTo2(target, transferBytes, channel, blocking);
        ReduceLength(transferBytes);
        return blockedBytes;
    }
    unsigned int BERGeneralDecoder::CopyRangeTo2(BufferedTransformation & target, unsigned long & begin, unsigned long end, const std::string & channel, bool blocking) const
    {
        if (m_definiteLength)
        end = STDMIN((unsigned long) m_length, end);
        return m_inQueue.CopyRangeTo2(target, begin, end, channel, blocking);
    }
    unsigned int BERGeneralDecoder::ReduceLength(unsigned int delta)
    {
        if (m_definiteLength)
        {
            if (m_length < delta)
            BERDecodeError();
            m_length -= delta;
        }
        return delta;
    }
    DERGeneralEncoder::DERGeneralEncoder(BufferedTransformation & outQueue, byte asnTag)
    : m_outQueue(outQueue), m_finished(false), m_asnTag(asnTag)
    {
    }
    DERGeneralEncoder::DERGeneralEncoder(DERGeneralEncoder & outQueue, byte asnTag)
    : m_outQueue(outQueue), m_finished(false), m_asnTag(asnTag)
    {
    }
    DERGeneralEncoder::~ DERGeneralEncoder()
    {
        // avoid throwing in constructor:
        try
        {
            if (!m_finished)
            MessageEnd();
        }
        catch(...)
        {
        }
    }
    void DERGeneralEncoder::MessageEnd()
    {
        m_finished = true;
        unsigned int length = (unsigned int) CurrentSize();
        m_outQueue.Put(m_asnTag);
        DERLengthEncode(m_outQueue, length);
        TransferTo(m_outQueue);
    }
    // *************************************************************
    void X509PublicKey::BERDecode(BufferedTransformation & bt)
    {
        BERSequenceDecoder subjectPublicKeyInfo(bt);
        BERSequenceDecoder algorithm(subjectPublicKeyInfo);
        GetAlgorithmID() .BERDecodeAndCheck(algorithm);
        bool parametersPresent = algorithm.EndReached() ? false: BERDecodeAlgorithmParameters(algorithm);
        algorithm.MessageEnd();
        BERGeneralDecoder subjectPublicKey(subjectPublicKeyInfo, BIT_STRING);
        subjectPublicKey.CheckByte(0);
        // unused bits
        BERDecodeKey2(subjectPublicKey, parametersPresent, subjectPublicKey.RemainingLength());
        subjectPublicKey.MessageEnd();
        subjectPublicKeyInfo.MessageEnd();
    }
    void X509PublicKey::DEREncode(BufferedTransformation & bt) const
    {
        DERSequenceEncoder subjectPublicKeyInfo(bt);
        DERSequenceEncoder algorithm(subjectPublicKeyInfo);
        GetAlgorithmID() .DEREncode(algorithm);
        DEREncodeAlgorithmParameters(algorithm);
        algorithm.MessageEnd();
        DERGeneralEncoder subjectPublicKey(subjectPublicKeyInfo, BIT_STRING);
        subjectPublicKey.Put(0);
        // unused bits
        DEREncodeKey(subjectPublicKey);
        subjectPublicKey.MessageEnd();
        subjectPublicKeyInfo.MessageEnd();
    }
    void PKCS8PrivateKey::BERDecode(BufferedTransformation & bt)
    {
        BERSequenceDecoder privateKeyInfo(bt);
        word32 version;
        BERDecodeUnsigned <word32 > (privateKeyInfo, version, INTEGER, 0, 0);
        // check version
        BERSequenceDecoder algorithm(privateKeyInfo);
        GetAlgorithmID() .BERDecodeAndCheck(algorithm);
        bool parametersPresent = BERDecodeAlgorithmParameters(algorithm);
        algorithm.MessageEnd();
        BERGeneralDecoder octetString(privateKeyInfo, OCTET_STRING);
        BERDecodeKey2(octetString, parametersPresent, privateKeyInfo.RemainingLength());
        octetString.MessageEnd();
        BERDecodeOptionalAttributes(privateKeyInfo);
        privateKeyInfo.MessageEnd();
    }
    void PKCS8PrivateKey::DEREncode(BufferedTransformation & bt) const
    {
        DERSequenceEncoder privateKeyInfo(bt);
        DEREncodeUnsigned <word32 > (privateKeyInfo, 0);
        // version
        DERSequenceEncoder algorithm(privateKeyInfo);
        GetAlgorithmID() .DEREncode(algorithm);
        DEREncodeAlgorithmParameters(algorithm);
        algorithm.MessageEnd();
        DERGeneralEncoder octetString(privateKeyInfo, OCTET_STRING);
        DEREncodeKey(octetString);
        octetString.MessageEnd();
        DEREncodeOptionalAttributes(privateKeyInfo);
        privateKeyInfo.MessageEnd();
    }
    //faz:base64.cpp - written and placed in the public domain by Wei Dai
    static const byte s_vec[] =
    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
    static const byte s_padding = '=';
    void Base64Encoder::IsolatedInitialize(const NameValuePairs & parameters)
    {
        bool insertLineBreaks = parameters.GetValueWithDefault("InsertLineBreaks", true);
        int maxLineLength = parameters.GetIntValueWithDefault("MaxLineLength", 72);
        const char * lineBreak = insertLineBreaks ? "\n": "";
        m_filter->Initialize(CombinedNameValuePairs(
        parameters,
        MakeParameters("EncodingLookupArray", (const byte *) s_vec)
        ("PaddingByte", s_padding)
        ("Log2Base", 6)
        ("GroupSize", insertLineBreaks ? maxLineLength: 0)
        ("Separator", ConstByteArrayParameter(lineBreak))
        ("Terminator", ConstByteArrayParameter(lineBreak))));
    }
    const int * Base64Decoder::GetDecodingLookupArray()
    {
        static bool s_initialized = false;
        static int s_array[256];
        if (!s_initialized)
        {
            InitializeDecodingLookupArray(s_array, s_vec, 64, false);
            s_initialized = true;
        }
        return s_array;
    }
    // basecode.cpp - written and placed in the public domain by Wei Dai
    void BaseN_Encoder::IsolatedInitialize(const NameValuePairs & parameters)
    {
        parameters.GetRequiredParameter("BaseN_Encoder", "EncodingLookupArray", m_alphabet);
        parameters.GetRequiredIntParameter("BaseN_Encoder", "Log2Base", m_bitsPerChar);
        if (m_bitsPerChar <= 0 || m_bitsPerChar >= 8)
        throw InvalidArgument("BaseN_Encoder: Log2Base must be between 1 and 7 inclusive");
        byte padding;
        bool pad;
        if (parameters.GetValue("PaddingByte", padding))
        pad = parameters.GetValueWithDefault("Pad", true);
        else
        pad = false;
        m_padding = pad ? padding: - 1;
        m_bytePos = m_bitPos = 0;
        int i = 8;
        while (i% m_bitsPerChar != 0)
        i += 8;
        m_outputBlockSize = i/ m_bitsPerChar;
        m_outBuf.New(m_outputBlockSize);
    }
    unsigned int BaseN_Encoder::Put2(const byte * begin, unsigned int length, int messageEnd, bool blocking)
    {
        FILTER_BEGIN;
        while (m_inputPosition < length)
        {
            if (m_bytePos == 0)
            memset(m_outBuf, 0, m_outputBlockSize);
            {
                unsigned int b = begin[m_inputPosition++], bitsLeftInSource = 8;
                while (true)
                {
                    assert(m_bitPos < m_bitsPerChar);
                    unsigned int bitsLeftInTarget = m_bitsPerChar - m_bitPos;
                    m_outBuf[m_bytePos] |= b >> (8 - bitsLeftInTarget);
                    if (bitsLeftInSource >= bitsLeftInTarget)
                    {
                        m_bitPos = 0;
                        ++m_bytePos;
                        bitsLeftInSource -= bitsLeftInTarget;
                        if (bitsLeftInSource == 0)
                        break;
                        b <<= bitsLeftInTarget;
                        b &= 0xff;
                    }
                    else
                    {
                        m_bitPos += bitsLeftInSource;
                        break;
                    }
                }
            }
            assert(m_bytePos <= m_outputBlockSize);
            if (m_bytePos == m_outputBlockSize)
            {
                int i;
                for (i = 0 ; i < m_bytePos ; i++)
                {
                    assert(m_outBuf[i] < (1 << m_bitsPerChar));
                    m_outBuf[i] = m_alphabet[m_outBuf[i]];
                }
                FILTER_OUTPUT(1, m_outBuf, m_outputBlockSize, 0);
                m_bytePos = m_bitPos = 0;
            }
        }
        if (messageEnd)
        {
            if (m_bitPos > 0)
            ++m_bytePos;
            int i;
            for (i = 0 ; i < m_bytePos ; i++)
            m_outBuf[i] = m_alphabet[m_outBuf[i]];
            if (m_padding != - 1 && m_bytePos > 0)
            {
                memset(m_outBuf + m_bytePos, m_padding, m_outputBlockSize - m_bytePos);
                m_bytePos = m_outputBlockSize;
            }
            FILTER_OUTPUT(2, m_outBuf, m_bytePos, messageEnd);
            m_bytePos = m_bitPos = 0;
        }
        FILTER_END_NO_MESSAGE_END;
    }
    void BaseN_Decoder::IsolatedInitialize(const NameValuePairs & parameters)
    {
        parameters.GetRequiredParameter("BaseN_Decoder", "DecodingLookupArray", m_lookup);
        parameters.GetRequiredIntParameter("BaseN_Decoder", "Log2Base", m_bitsPerChar);
        if (m_bitsPerChar <= 0 || m_bitsPerChar >= 8)
        throw InvalidArgument("BaseN_Decoder: Log2Base must be between 1 and 7 inclusive");
        m_bytePos = m_bitPos = 0;
        int i = m_bitsPerChar;
        while (i% 8 != 0)
        i += m_bitsPerChar;
        m_outputBlockSize = i/ 8;
        m_outBuf.New(m_outputBlockSize);
    }
    unsigned int BaseN_Decoder::Put2(const byte * begin, unsigned int length, int messageEnd, bool blocking)
    {
        FILTER_BEGIN;
        while (m_inputPosition < length)
        {
            unsigned int value;
            value = m_lookup[begin[m_inputPosition++]];
            if (value >= 256)
            continue;
            if (m_bytePos == 0 && m_bitPos == 0)
            memset(m_outBuf, 0, m_outputBlockSize);
            {
                int newBitPos = m_bitPos + m_bitsPerChar;
                if (newBitPos <= 8)
                m_outBuf[m_bytePos] |= value << (8 - newBitPos);
                else
                {
                    m_outBuf[m_bytePos] |= value >> (newBitPos - 8);
                    m_outBuf[m_bytePos + 1] |= value << (16 - newBitPos);
                }
                m_bitPos = newBitPos;
                while (m_bitPos >= 8)
                {
                    m_bitPos -= 8;
                    ++m_bytePos;
                }
            }
            if (m_bytePos == m_outputBlockSize)
            {
                FILTER_OUTPUT(1, m_outBuf, m_outputBlockSize, 0);
                m_bytePos = m_bitPos = 0;
            }
        }
        if (messageEnd)
        {
            FILTER_OUTPUT(2, m_outBuf, m_bytePos, messageEnd);
            m_bytePos = m_bitPos = 0;
        }
        FILTER_END_NO_MESSAGE_END;
    }
    void BaseN_Decoder::InitializeDecodingLookupArray(int * lookup, const byte * alphabet, unsigned int base, bool caseInsensitive)
    {
        std::fill(lookup, lookup + 256, - 1);
        for (unsigned int i = 0 ; i < base ; i++)
        {
            if (caseInsensitive && isalpha(alphabet[i]))
            {
                assert(lookup[toupper(alphabet[i]) ] == - 1);
                lookup[toupper(alphabet[i]) ] = i;
                assert(lookup[tolower(alphabet[i]) ] == - 1);
                lookup[tolower(alphabet[i]) ] = i;
            }
            else
            {
                assert(lookup[alphabet[i]] == - 1);
                lookup[alphabet[i]] = i;
            }
        }
    }
    void Grouper::IsolatedInitialize(const NameValuePairs & parameters)
    {
        m_groupSize = parameters.GetIntValueWithDefault("GroupSize", 0);
        ConstByteArrayParameter separator, terminator;
        if (m_groupSize)
        parameters.GetRequiredParameter("Grouper", "Separator", separator);
        parameters.GetValue("Terminator", terminator);
        m_separator.Assign(separator.begin(), separator.size());
        m_terminator.Assign(terminator.begin(), terminator.size());
        m_counter = 0;
    }
    unsigned int Grouper::Put2(const byte * begin, unsigned int length, int messageEnd, bool blocking)
    {
        FILTER_BEGIN;
        if (m_groupSize)
        {
            while (m_inputPosition < length)
            {
                if (m_counter == m_groupSize)
                {
                    FILTER_OUTPUT(1, m_separator, m_separator.size(), 0);
                    m_counter = 0;
                }
                unsigned int len;
                FILTER_OUTPUT2(2, len = STDMIN(length - m_inputPosition, m_groupSize - m_counter),
                begin + m_inputPosition, len, 0);
                m_inputPosition += len;
                m_counter += len;
            }
        }
        else
        FILTER_OUTPUT(3, begin, length, 0);
        if (messageEnd)
        FILTER_OUTPUT(4, m_terminator, m_terminator.size(), messageEnd);
        FILTER_END_NO_MESSAGE_END
    }
    // cryptlib.cpp - written and placed in the public domain by Wei Dai
    CRYPTOPP_COMPILE_ASSERT(sizeof(byte) == 1);
    CRYPTOPP_COMPILE_ASSERT(sizeof(word16) == 2);
    CRYPTOPP_COMPILE_ASSERT(sizeof(word32) == 4);
#ifdef WORD64_AVAILABLE
    CRYPTOPP_COMPILE_ASSERT(sizeof(word64) == 8);
#endif
    CRYPTOPP_COMPILE_ASSERT(sizeof(dword) == 2 * sizeof(word));
    const std::string BufferedTransformation::NULL_CHANNEL;
    const NullNameValuePairs g_nullNameValuePairs;
    BufferedTransformation & TheBitBucket()
    {
        static BitBucket bitBucket;
        return bitBucket;
    }
    Algorithm::Algorithm(bool checkSelfTestStatus)
    {
        if (checkSelfTestStatus && FIPS_140_2_ComplianceEnabled())
        {
            if (GetPowerUpSelfTestStatus() == POWER_UP_SELF_TEST_NOT_DONE && !PowerUpSelfTestInProgressOnThisThread())
            throw SelfTestFailure("Cryptographic algorithms are disabled before the power-up self tests are performed.");
            if (GetPowerUpSelfTestStatus() == POWER_UP_SELF_TEST_FAILED)
            throw SelfTestFailure("Cryptographic algorithms are disabled after power-up a self test failed.");
        }
    }
    void SimpleKeyingInterface::SetKeyWithRounds(const byte * key, unsigned int length, int rounds)
    {
        SetKey(key, length, MakeParameters(Name::Rounds(), rounds));
    }
    void SimpleKeyingInterface::SetKeyWithIV(const byte * key, unsigned int length, const byte * iv)
    {
        SetKey(key, length, MakeParameters(Name::IV(), iv));
    }
    void SimpleKeyingInterface::ThrowIfInvalidKeyLength(const Algorithm & algorithm, unsigned int length)
    {
        if (!IsValidKeyLength(length))
        throw InvalidKeyLength(algorithm.AlgorithmName(), length);
    }
    void BlockTransformation::ProcessAndXorMultipleBlocks(const byte * inBlocks, const byte * xorBlocks, byte * outBlocks, unsigned int numberOfBlocks) const
    {
        unsigned int blockSize = BlockSize();
        while (numberOfBlocks--)
        {
            ProcessAndXorBlock(inBlocks, xorBlocks, outBlocks);
            inBlocks += blockSize;
            outBlocks += blockSize;
            if (xorBlocks)
            xorBlocks += blockSize;
        }
    }
    void StreamTransformation::ProcessLastBlock(byte * outString, const byte * inString, unsigned int length)
    {
        assert(MinLastBlockSize() == 0);
        // this function should be overriden otherwise
        if (length == MandatoryBlockSize())
        ProcessData(outString, inString, length);
        else if(length != 0)
        throw NotImplemented("StreamTransformation: this object does't support a special last block");
    }
    unsigned int RandomNumberGenerator::GenerateBit()
    {
        return Parity(GenerateByte());
    }
    void RandomNumberGenerator::GenerateBlock(byte * output, unsigned int size)
    {
        while (size--)
        * output++= GenerateByte();
    }
    word32 RandomNumberGenerator::GenerateWord32(word32 min, word32 max)
    {
        word32 range = max - min;
        const int maxBytes = BytePrecision(range);
        const int maxBits = BitPrecision(range);
        word32 value;
        do
        {
            value = 0;
            for (int i = 0 ; i < maxBytes ; i++)
            value = (value << 8) | GenerateByte();
            value = Crop(value, maxBits);
        }
        while (value > range);
        return value + min;
    }
    void RandomNumberGenerator::DiscardBytes(unsigned int n)
    {
        while (n--)
        GenerateByte();
    }
    RandomNumberGenerator & NullRNG()
    {
        class NullRNG: public RandomNumberGenerator
        {
            public:
            std::string AlgorithmName() const
            {
                return "NullRNG";
            }
            byte GenerateByte()
            {
                throw NotImplemented("NullRNG: NullRNG should only be passed to functions that don't need to generate random bytes");
            }
                };
        static NullRNG s_nullRNG;
        return s_nullRNG;
    }
    bool HashTransformation::TruncatedVerify(const byte * digestIn, unsigned int digestLength)
    {
        ThrowIfInvalidTruncatedSize(digestLength);
        SecByteBlock digest(digestLength);
        xmTF(digest, digestLength);
        return memcmp(digest, digestIn, digestLength) == 0;
    }
    void HashTransformation::ThrowIfInvalidTruncatedSize(unsigned int size) const
    {
        if (size > DigestSize())
        throw InvalidArgument("HashTransformation: can't truncate a " + IntToString(DigestSize()) + " byte digest to " + IntToString(size) + " bytes");
    }
    unsigned int BufferedTransformation::GetMaxWaitObjectCount() const
    {
        const BufferedTransformation * t = AttachedTransformation();
        return t ? t->GetMaxWaitObjectCount(): 0;
    }
    void BufferedTransformation::GetWaitObjects(WaitObjectContainer & container)
    {
        BufferedTransformation * t = AttachedTransformation();
        if (t)
        t->GetWaitObjects(container);
    }
    void BufferedTransformation::Initialize(const NameValuePairs & parameters, int propagation)
    {
        assert(!AttachedTransformation());
        IsolatedInitialize(parameters);
    }
    bool BufferedTransformation::Flush(bool hardFlush, int propagation, bool blocking)
    {
        assert(!AttachedTransformation());
        return IsolatedFlush(hardFlush, blocking);
    }
    bool BufferedTransformation::MessageSeriesEnd(int propagation, bool blocking)
    {
        assert(!AttachedTransformation());
        return IsolatedMessageSeriesEnd(blocking);
    }
    byte * BufferedTransformation::ChannelCreatePutSpace(const std::string & channel, unsigned int & size)
    {
        if (channel.empty())
        return CreatePutSpace(size);
        else
        throw NoChannelSupport();
    }
    unsigned int BufferedTransformation::ChannelPut2(const std::string & channel, const byte * begin, unsigned int length, int messageEnd, bool blocking)
    {
        if (channel.empty())
        return Put2(begin, length, messageEnd, blocking);
        else
        throw NoChannelSupport();
    }
    unsigned int BufferedTransformation::ChannelPutModifiable2(const std::string & channel, byte * begin, unsigned int length, int messageEnd, bool blocking)
    {
        if (channel.empty())
        return PutModifiable2(begin, length, messageEnd, blocking);
        else
        return ChannelPut2(channel, begin, length, messageEnd, blocking);
    }
    void BufferedTransformation::ChannelInitialize(const std::string & channel, const NameValuePairs & parameters, int propagation)
    {
        if (channel.empty())
        Initialize(parameters, propagation);
        else
        throw NoChannelSupport();
    }
    bool BufferedTransformation::ChannelFlush(const std::string & channel, bool completeFlush, int propagation, bool blocking)
    {
        if (channel.empty())
        return Flush(completeFlush, propagation, blocking);
        else
        throw NoChannelSupport();
    }
    bool BufferedTransformation::ChannelMessageSeriesEnd(const std::string & channel, int propagation, bool blocking)
    {
        if (channel.empty())
        return MessageSeriesEnd(propagation, blocking);
        else
        throw NoChannelSupport();
    }
    unsigned long BufferedTransformation::MaxRetrievable() const
    {
        if (AttachedTransformation())
        return AttachedTransformation()->MaxRetrievable();
        else
        return CopyTo(TheBitBucket());
    }
    bool BufferedTransformation::AnyRetrievable() const
    {
        if (AttachedTransformation())
        return AttachedTransformation()->AnyRetrievable();
        else
        {
            byte b;
            return Peek(b) != 0;
        }
    }
    unsigned int BufferedTransformation::Get(byte & outByte)
    {
        if (AttachedTransformation())
        return AttachedTransformation()->Get(outByte);
        else
        return Get( & outByte, 1);
    }
    unsigned int BufferedTransformation::Get(byte * outString, unsigned int getMax)
    {
        if (AttachedTransformation())
        return AttachedTransformation()->Get(outString, getMax);
        else
        {
            ArraySink arraySink(outString, getMax);
            return TransferTo(arraySink, getMax);
        }
    }
    unsigned int BufferedTransformation::Peek(byte & outByte) const
    {
        if (AttachedTransformation())
        return AttachedTransformation()->Peek(outByte);
        else
        return Peek( & outByte, 1);
    }
    unsigned int BufferedTransformation::Peek(byte * outString, unsigned int peekMax) const
    {
        if (AttachedTransformation())
        return AttachedTransformation()->Peek(outString, peekMax);
        else
        {
            ArraySink arraySink(outString, peekMax);
            return CopyTo(arraySink, peekMax);
        }
    }
    unsigned long BufferedTransformation::Skip(unsigned long skipMax)
    {
        if (AttachedTransformation())
        return AttachedTransformation()->Skip(skipMax);
        else
        return TransferTo(TheBitBucket(), skipMax);
    }
    unsigned long BufferedTransformation::TotalBytesRetrievable() const
    {
        if (AttachedTransformation())
        return AttachedTransformation()->TotalBytesRetrievable();
        else
        return MaxRetrievable();
    }
    unsigned int BufferedTransformation::NumberOfMessages() const
    {
        if (AttachedTransformation())
        return AttachedTransformation()->NumberOfMessages();
        else
        return CopyMessagesTo(TheBitBucket());
    }
    bool BufferedTransformation::AnyMessages() const
    {
        if (AttachedTransformation())
        return AttachedTransformation()->AnyMessages();
        else
        return NumberOfMessages() != 0;
    }
    bool BufferedTransformation::GetNextMessage()
    {
        if (AttachedTransformation())
        return AttachedTransformation()->GetNextMessage();
        else
        {
            assert(!AnyMessages());
            return false;
        }
    }
    unsigned int BufferedTransformation::SkipMessages(unsigned int count)
    {
        if (AttachedTransformation())
        return AttachedTransformation()->SkipMessages(count);
        else
        return TransferMessagesTo(TheBitBucket(), count);
    }
    unsigned int BufferedTransformation::TransferMessagesTo2(BufferedTransformation & target, unsigned int & messageCount, const std::string & channel, bool blocking)
    {
        if (AttachedTransformation())
        return AttachedTransformation()->TransferMessagesTo2(target, messageCount, channel, blocking);
        else
        {
            unsigned int maxMessages = messageCount;
            for (messageCount = 0 ; messageCount < maxMessages && AnyMessages() ; messageCount++)
            {
                unsigned int blockedBytes;
                unsigned long transferedBytes;
                while (AnyRetrievable())
                {
                    transferedBytes = ULONG_MAX;
                    blockedBytes = TransferTo2(target, transferedBytes, channel, blocking);
                    if (blockedBytes > 0)
                    return blockedBytes;
                }
                if (target.ChannelMessageEnd(channel, GetAutoSignalPropagation(), blocking))
                return 1;
                bool result = GetNextMessage();
                assert(result);
            }
            return 0;
        }
    }
    unsigned int BufferedTransformation::CopyMessagesTo(BufferedTransformation & target, unsigned int count, const std::string & channel) const
    {
        if (AttachedTransformation())
        return AttachedTransformation()->CopyMessagesTo(target, count, channel);
        else
        return 0;
    }
    void BufferedTransformation::SkipAll()
    {
        if (AttachedTransformation())
        AttachedTransformation()->SkipAll();
        else
        {
            while (SkipMessages())
            {
            }
            while (Skip())
            {
            }
        }
    }
    unsigned int BufferedTransformation::TransferAllTo2(BufferedTransformation & target, const std::string & channel, bool blocking)
    {
        if (AttachedTransformation())
        return AttachedTransformation()->TransferAllTo2(target, channel, blocking);
        else
        {
            assert(!NumberOfMessageSeries());
            unsigned int messageCount;
            do
            {
                messageCount = UINT_MAX;
                unsigned int blockedBytes = TransferMessagesTo2(target, messageCount, channel, blocking);
                if (blockedBytes)
                return blockedBytes;
            }
            while (messageCount != 0);
            unsigned long byteCount;
            do
            {
                byteCount = ULONG_MAX;
                unsigned int blockedBytes = TransferTo2(target, byteCount, channel, blocking);
                if (blockedBytes)
                return blockedBytes;
            }
            while (byteCount != 0);
            return 0;
        }
    }
    void BufferedTransformation::CopyAllTo(BufferedTransformation & target, const std::string & channel) const
    {
        if (AttachedTransformation())
        AttachedTransformation()->CopyAllTo(target, channel);
        else
        {
            assert(!NumberOfMessageSeries());
            while (CopyMessagesTo(target, UINT_MAX, channel))
            {
            }
        }
    }
    void BufferedTransformation::SetRetrievalChannel(const std::string & channel)
    {
        if (AttachedTransformation())
        AttachedTransformation()->SetRetrievalChannel(channel);
    }
    unsigned int BufferedTransformation::ChannelPutWord16(const std::string & channel, word16 value, ByteOrder order, bool blocking)
    {
        FixedSizeSecBlock <byte, 2 > buf;
        PutWord(false, order, buf, value);
        return ChannelPut(channel, buf, 2, blocking);
    }
    unsigned int BufferedTransformation::ChannelPutWord32(const std::string & channel, word32 value, ByteOrder order, bool blocking)
    {
        FixedSizeSecBlock <byte, 4 > buf;
        PutWord(false, order, buf, value);
        return ChannelPut(channel, buf, 4, blocking);
    }
    unsigned int BufferedTransformation::PutWord16(word16 value, ByteOrder order, bool blocking)
    {
        return ChannelPutWord16(NULL_CHANNEL, value, order, blocking);
    }
    unsigned int BufferedTransformation::PutWord32(word32 value, ByteOrder order, bool blocking)
    {
        return ChannelPutWord32(NULL_CHANNEL, value, order, blocking);
    }
    unsigned int BufferedTransformation::PeekWord16(word16 & value, ByteOrder order)
    {
        byte buf[2] =
        {
            0, 0
                };
        unsigned int len = Peek(buf, 2);
        if (order)
        value = (buf[0] << 8) | buf[1];
        else
        value = (buf[1] << 8) | buf[0];
        return len;
    }
    unsigned int BufferedTransformation::PeekWord32(word32 & value, ByteOrder order)
    {
        byte buf[4] =
        {
            0, 0, 0, 0
                };
        unsigned int len = Peek(buf, 4);
        if (order)
        value = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf [3];
        else
        value = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf [0];
        return len;
    }
    unsigned int BufferedTransformation::GetWord16(word16 & value, ByteOrder order)
    {
        return Skip(PeekWord16(value, order));
    }
    unsigned int BufferedTransformation::GetWord32(word32 & value, ByteOrder order)
    {
        return Skip(PeekWord32(value, order));
    }
    void BufferedTransformation::Attach(BufferedTransformation * newOut)
    {
        if (AttachedTransformation() && AttachedTransformation()->Attachable())
        AttachedTransformation()->Attach(newOut);
        else
        Detach(newOut);
    }
    void GeneratableCryptoMaterial::GenerateRandomWithKeySize(RandomNumberGenerator & rng, unsigned int keySize)
    {
        GenerateRandom(rng, MakeParameters("KeySize", (int) keySize));
    }
    BufferedTransformation * PK_Encryptor::CreateEncryptionFilter(RandomNumberGenerator & rng, BufferedTransformation * attachment) const
    {
        struct EncryptionFilter: public Unflushable <FilterWithInputQueue >
        {
            // VC60 complains if this function is missing
            EncryptionFilter(const EncryptionFilter & x): Unflushable <FilterWithInputQueue > (NULL), m_rng(x.m_rng), m_encryptor(x.m_encryptor)
            {
            }
            EncryptionFilter(RandomNumberGenerator & rng, const PK_Encryptor & encryptor, BufferedTransformation * attachment)
            : Unflushable <FilterWithInputQueue > (attachment), m_rng(rng), m_encryptor(encryptor)
            {
            }
            bool IsolatedMessageEnd(bool blocking)
            {
                switch (m_continueAt)
                {
                case 0:
                    {
                        unsigned int plaintextLength = m_inQueue.CurrentSize();
                        m_ciphertextLength = m_encryptor.CiphertextLength(plaintextLength);
                        SecByteBlock plaintext(plaintextLength);
                        m_inQueue.Get(plaintext, plaintextLength);
                        m_ciphertext.resize(m_ciphertextLength);
                        m_encryptor.Encrypt(m_rng, plaintext, plaintextLength, m_ciphertext);
                    }
                case 1:
                    if (!Output(1, m_ciphertext, m_ciphertextLength, 0, blocking))
                    return false;
                                };
                return true;
            }
            RandomNumberGenerator & m_rng;
            const PK_Encryptor & m_encryptor;
            unsigned int m_ciphertextLength;
            SecByteBlock m_ciphertext;
                };
        return new EncryptionFilter(rng, * this, attachment);
    }
    BufferedTransformation * PK_Decryptor::CreateDecryptionFilter(RandomNumberGenerator & rng, BufferedTransformation * attachment) const
    {
        struct DecryptionFilter: public Unflushable <FilterWithInputQueue >
        {
            // VC60 complains if this function is missing
            DecryptionFilter(const DecryptionFilter & x): Unflushable <FilterWithInputQueue > (NULL), m_rng(x.m_rng), m_decryptor(x.m_decryptor)
            {
            }
            DecryptionFilter(RandomNumberGenerator & rng, const PK_Decryptor & decryptor, BufferedTransformation * attachment)
            : Unflushable <FilterWithInputQueue > (attachment), m_rng(rng), m_decryptor(decryptor)
            {
            }
            bool IsolatedMessageEnd(bool blocking)
            {
                switch (m_continueAt)
                {
                case 0:
                    {
                        unsigned int ciphertextLength = m_inQueue.CurrentSize();
                        unsigned int maxPlaintextLength = m_decryptor.MaxPlaintextLength(ciphertextLength);
                        SecByteBlock ciphertext(ciphertextLength);
                        m_inQueue.Get(ciphertext, ciphertextLength);
                        m_plaintext.resize(maxPlaintextLength);
                        m_result = m_decryptor.Decrypt(m_rng, ciphertext, ciphertextLength, m_plaintext);
                        if (!m_result.isValidCoding)
                        throw InvalidCiphertext(m_decryptor.AlgorithmName() + ": invalid ciphertext");
                    }
                case 1:
                    if (!Output(1, m_plaintext, m_result.messageLength, 0, blocking))
                    return false;
                }
                return true;
            }
            RandomNumberGenerator & m_rng;
            const PK_Decryptor & m_decryptor;
            SecByteBlock m_plaintext;
            DecodingResult m_result;
                };
        return new DecryptionFilter(rng, * this, attachment);
    }
    unsigned int PK_FixedLengthCryptoSystem::MaxPlaintextLength(unsigned int cipherTextLength) const
    {
        if (cipherTextLength == FixedCiphertextLength())
        return FixedMaxPlaintextLength();
        else
        return 0;
    }
    unsigned int PK_FixedLengthCryptoSystem::CiphertextLength(unsigned int plainTextLength) const
    {
        if (plainTextLength <= FixedMaxPlaintextLength())
        return FixedCiphertextLength();
        else
        return 0;
    }
    DecodingResult PK_FixedLengthDecryptor::Decrypt(RandomNumberGenerator & rng, const byte * cipherText, unsigned int cipherTextLength, byte * plainText) const
    {
        if (cipherTextLength != FixedCiphertextLength())
        return DecodingResult();
        return FixedLengthDecrypt(rng, cipherText, plainText);
    }
    unsigned int PK_Signer::Sign(RandomNumberGenerator & rng, PK_MessageAccumulator * messageAccumulator, byte * signature) const
    {
        std::auto_ptr <PK_MessageAccumulator > m(messageAccumulator);
        return SignAndRestart(rng, * m, signature, false);
    }
    unsigned int PK_Signer::SignMessage(RandomNumberGenerator & rng, const byte * message, unsigned int messageLen, byte * signature) const
    {
        std::auto_ptr <PK_MessageAccumulator > m(NewSignatureAccumulator(rng));
        m->Update(message, messageLen);
        return SignAndRestart(rng, * m, signature, false);
    }
    bool PK_Verifier::Verify(PK_MessageAccumulator * messageAccumulator) const
    {
        std::auto_ptr <PK_MessageAccumulator > m(messageAccumulator);
        return VerifyAndRestart( * m);
    }
    bool PK_Verifier::VerifyMessage(const byte * message, unsigned int messageLen, const byte * signature, unsigned int signatureLength) const
    {
        std::auto_ptr <PK_MessageAccumulator > m(NewVerificationAccumulator());
        InputSignature( * m, signature, signatureLength);
        m->Update(message, messageLen);
        return VerifyAndRestart( * m);
    }
    // eprecomp.cpp - written and placed in the public domain by Wei Dai
    template <class T > void DL_FixedBasePrecomputationImpl <T >::SetBase(const DL_GroupPrecomputation < Element > & group, const Element & i_base)
    {
        m_base = group.NeedConversions() ? group.ConvertIn(i_base): i_base;
        if (m_bases.empty() || ! (m_base == m_bases[0]))
        {
            m_bases.resize(1);
            m_bases[0] = m_base;
        }
        if (group.NeedConversions())
        m_base = i_base;
    }
    template <class T > void DL_FixedBasePrecomputationImpl <T >::Precompute(const DL_GroupPrecomputation < Element > & group, unsigned int maxExpBits, unsigned int storage)
    {
        assert(m_bases.size() > 0);
        assert(storage <= maxExpBits);
        if (storage > 1)
        {
            m_windowSize = (maxExpBits + storage - 1) / storage;
            m_exponentBase = Integer::Power2(m_windowSize);
        }
        m_bases.resize(storage);
        for (unsigned i = 1 ; i < storage ; i++)
        m_bases[i] = group.GetGroup() .ScalarMultiply(m_bases[i - 1], m_exponentBase);
    }
    template <class T > void DL_FixedBasePrecomputationImpl <T >::Load(const DL_GroupPrecomputation < Element > & group, BufferedTransformation & bt)
    {
        BERSequenceDecoder seq(bt);
        word32 version;
        BERDecodeUnsigned <word32 > (seq, version, INTEGER, 1, 1);
        m_exponentBase.BERDecode(seq);
        m_windowSize = m_exponentBase.BitCount() - 1;
        m_bases.clear();
        while (!seq.EndReached())
        m_bases.push_back(group.BERDecodeElement(seq));
        if (!m_bases.empty() && group.NeedConversions())
        m_base = group.ConvertOut(m_bases[0]);
        seq.MessageEnd();
    }
    template <class T > void DL_FixedBasePrecomputationImpl <T >::Save(const DL_GroupPrecomputation < Element > & group, BufferedTransformation & bt) const
    {
        DERSequenceEncoder seq(bt);
        DEREncodeUnsigned <word32 > (seq, 1);
        // version
        m_exponentBase.DEREncode(seq);
        for (unsigned i = 0 ; i < m_bases.size() ; i++)
        group.DEREncodeElement(seq, m_bases[i]);
        seq.MessageEnd();
    }
    template <class T > void DL_FixedBasePrecomputationImpl <T >::PrepareCascade(const DL_GroupPrecomputation < Element > & i_group, std::vector < BaseAndExponent < Element > > & eb, const Integer & exponent) const
    {
        const AbstractGroup <T > & group = i_group.GetGroup();
        Integer r, q, e = exponent;
        bool fastNegate = group.InversionIsFast() && m_windowSize > 1;
        unsigned int i;
        for (i = 0 ; i + 1 < m_bases.size() ; i++)
        {
            Integer::DivideByPowerOf2(r, q, e, m_windowSize);
            std::swap(q, e);
            if (fastNegate && r.GetBit(m_windowSize - 1))
            {
                ++e;
                eb.push_back(BaseAndExponent < Element > (group.Inverse(m_bases[i]), m_exponentBase - r));
            }
            else
            eb.push_back(BaseAndExponent < Element > (m_bases[i], r));
        }
        eb.push_back(BaseAndExponent < Element > (m_bases[i], e));
    }
    template <class T > T DL_FixedBasePrecomputationImpl <T >::Exponentiate(const DL_GroupPrecomputation < Element > & group, const Integer & exponent) const
    {
        std::vector <BaseAndExponent <Element > > eb;
        // array of segments of the exponent and precalculated bases
        eb.reserve(m_bases.size());
        PrepareCascade(group, eb, exponent);
        return group.ConvertOut(GeneralCascadeMultiplication < Element > (group.GetGroup(), eb.begin(), eb.end()));
    }
    template <class T > T
    DL_FixedBasePrecomputationImpl <T >::CascadeExponentiate(const DL_GroupPrecomputation < Element > & group, const Integer & exponent,
    const DL_FixedBasePrecomputation < T > & i_pc2, const Integer & exponent2) const
    {
        std::vector <BaseAndExponent <Element > > eb;
        // array of segments of the exponent and precalculated bases
        const DL_FixedBasePrecomputationImpl <T > & pc2 = static_cast <const DL_FixedBasePrecomputationImpl <T > &> (i_pc2);
        eb.reserve(m_bases.size() + pc2.m_bases.size());
        PrepareCascade(group, eb, exponent);
        pc2.PrepareCascade(group, eb, exponent2);
        return group.ConvertOut(GeneralCascadeMultiplication < Element > (group.GetGroup(), eb.begin(), eb.end()));
    }
    // filters.cpp - written and placed in the public domain by Wei Dai
    Filter::Filter(BufferedTransformation * attachment)
    : m_attachment(attachment), m_continueAt(0)
    {
    }
    BufferedTransformation * Filter::NewDefaultAttachment() const
    {
        return new MessageQueue;
    }
    BufferedTransformation * Filter::AttachedTransformation()
    {
        if (m_attachment.get() == NULL)
        m_attachment.reset(NewDefaultAttachment());
        return m_attachment.get();
    }
    const BufferedTransformation * Filter::AttachedTransformation() const
    {
        if (m_attachment.get() == NULL)
        const_cast <Filter *> (this)->m_attachment.reset(NewDefaultAttachment());
        return m_attachment.get();
    }
    void Filter::Detach(BufferedTransformation * newOut)
    {
        m_attachment.reset(newOut);
        NotifyAttachmentChange();
    }
    void Filter::Insert(Filter * filter)
    {
        filter->m_attachment.reset(m_attachment.release());
        m_attachment.reset(filter);
        NotifyAttachmentChange();
    }
    unsigned int Filter::CopyRangeTo2(BufferedTransformation & target, unsigned long & begin, unsigned long end, const std::string & channel, bool blocking) const
    {
        return AttachedTransformation()->CopyRangeTo2(target, begin, end, channel, blocking);
    }
    unsigned int Filter::TransferTo2(BufferedTransformation & target, unsigned long & transferBytes, const std::string & channel, bool blocking)
    {
        return AttachedTransformation()->TransferTo2(target, transferBytes, channel, blocking);
    }
    void Filter::Initialize(const NameValuePairs & parameters, int propagation)
    {
        m_continueAt = 0;
        IsolatedInitialize(parameters);
        PropagateInitialize(parameters, propagation);
    }
    bool Filter::Flush(bool hardFlush, int propagation, bool blocking)
    {
        switch (m_continueAt)
        {
        case 0:
            if (IsolatedFlush(hardFlush, blocking))
            return true;
        case 1:
            if (OutputFlush(1, hardFlush, propagation, blocking))
            return true;
        }
        return false;
    }
    bool Filter::MessageSeriesEnd(int propagation, bool blocking)
    {
        switch (m_continueAt)
        {
        case 0:
            if (IsolatedMessageSeriesEnd(blocking))
            return true;
        case 1:
            if (ShouldPropagateMessageSeriesEnd() && OutputMessageSeriesEnd(1, propagation, blocking))
            return true;
        }
        return false;
    }
    void Filter::PropagateInitialize(const NameValuePairs & parameters, int propagation, const std::string & channel)
    {
        if (propagation)
        AttachedTransformation()->ChannelInitialize(channel, parameters, propagation - 1);
    }
    unsigned int Filter::Output(int outputSite, const byte * inString, unsigned int length, int messageEnd, bool blocking, const std::string & channel)
    {
        if (messageEnd)
        messageEnd--;
        unsigned int result = AttachedTransformation()->Put2(inString, length, messageEnd, blocking);
        m_continueAt = result ? outputSite: 0;
        return result;
    }
    bool Filter::OutputFlush(int outputSite, bool hardFlush, int propagation, bool blocking, const std::string & channel)
    {
        if (propagation && AttachedTransformation()->ChannelFlush(channel, hardFlush, propagation - 1, blocking))
        {
            m_continueAt = outputSite;
            return true;
        }
        m_continueAt = 0;
        return false;
    }
    bool Filter::OutputMessageSeriesEnd(int outputSite, int propagation, bool blocking, const std::string & channel)
    {
        if (propagation && AttachedTransformation()->ChannelMessageSeriesEnd(channel, propagation - 1, blocking))
        {
            m_continueAt = outputSite;
            return true;
        }
        m_continueAt = 0;
        return false;
    }
    // *************************************************************
    unsigned int MeterFilter::Put2(const byte * begin, unsigned int length, int messageEnd, bool blocking)
    {
        if (m_transparent)
        {
            FILTER_BEGIN;
            m_currentMessageBytes += length;
            m_totalBytes += length;
            if (messageEnd)
            {
                m_currentMessageBytes = 0;
                m_currentSeriesMessages++;
                m_totalMessages++;
            }
            FILTER_OUTPUT(1, begin, length, messageEnd);
            FILTER_END_NO_MESSAGE_END;
        }
        return 0;
    }
    bool MeterFilter::IsolatedMessageSeriesEnd(bool blocking)
    {
        m_currentMessageBytes = 0;
        m_currentSeriesMessages = 0;
        m_totalMessageSeries++;
        return false;
    }
    // *************************************************************
    void FilterWithBufferedInput::BlockQueue::ResetQueue(unsigned int blockSize, unsigned int maxBlocks)
    {
        m_buffer.New(blockSize * maxBlocks);
        m_blockSize = blockSize;
        m_maxBlocks = maxBlocks;
        m_size = 0;
        m_begin = m_buffer;
    }
    byte * FilterWithBufferedInput::BlockQueue::GetBlock()
    {
        if (m_size >= m_blockSize)
        {
            byte * ptr = m_begin;
            if ((m_begin += m_blockSize) == m_buffer.end())
            m_begin = m_buffer;
            m_size -= m_blockSize;
            return ptr;
        }
        else
        return NULL;
    }
    byte * FilterWithBufferedInput::BlockQueue::GetContigousBlocks(unsigned int & numberOfBytes)
    {
        numberOfBytes = STDMIN(numberOfBytes, STDMIN((unsigned int)(m_buffer.end() - m_begin), m_size));
        byte * ptr = m_begin;
        m_begin += numberOfBytes;
        m_size -= numberOfBytes;
        if (m_size == 0 || m_begin == m_buffer.end())
        m_begin = m_buffer;
        return ptr;
    }
    unsigned int FilterWithBufferedInput::BlockQueue::GetAll(byte * outString)
    {
        unsigned int size = m_size;
        unsigned int numberOfBytes = m_maxBlocks * m_blockSize;
        const byte * ptr = GetContigousBlocks(numberOfBytes);
        memcpy(outString, ptr, numberOfBytes);
        memcpy(outString + numberOfBytes, m_begin, m_size);
        m_size = 0;
        return size;
    }
    void FilterWithBufferedInput::BlockQueue::Put(const byte * inString, unsigned int length)
    {
        assert(m_size + length <= m_buffer.size());
        byte * end = (m_size < (unsigned int)(m_buffer.end() - m_begin)) ? m_begin + m_size: m_begin + m_size - m_buffer.size();
        unsigned int len = STDMIN(length, (unsigned int)(m_buffer.end() - end));
        memcpy(end, inString, len);
        if (len < length)
        memcpy(m_buffer, inString + len, length - len);
        m_size += length;
    }
    FilterWithBufferedInput::FilterWithBufferedInput(BufferedTransformation * attachment)
    : Filter(attachment)
    {
    }
    FilterWithBufferedInput::FilterWithBufferedInput(unsigned int firstSize, unsigned int blockSize, unsigned int lastSize, BufferedTransformation * attachment)
    : Filter(attachment), m_firstSize(firstSize), m_blockSize(blockSize), m_lastSize(lastSize)
    , m_firstInputDone(false)
    {
        if (m_firstSize < 0 || m_blockSize < 1 || m_lastSize < 0)
        throw InvalidArgument("FilterWithBufferedInput: invalid buffer size");
        m_queue.ResetQueue(1, m_firstSize);
    }
    void FilterWithBufferedInput::IsolatedInitialize(const NameValuePairs & parameters)
    {
        InitializeDerivedAndReturnNewSizes(parameters, m_firstSize, m_blockSize, m_lastSize);
        if (m_firstSize < 0 || m_blockSize < 1 || m_lastSize < 0)
        throw InvalidArgument("FilterWithBufferedInput: invalid buffer size");
        m_queue.ResetQueue(1, m_firstSize);
        m_firstInputDone = false;
    }
    bool FilterWithBufferedInput::IsolatedFlush(bool hardFlush, bool blocking)
    {
        if (!blocking)
        throw BlockingInputOnly("FilterWithBufferedInput");
        if (hardFlush)
        ForceNextPut();
        FlushDerived();
        return false;
    }
    unsigned int FilterWithBufferedInput::PutMaybeModifiable(byte * inString, unsigned int length, int messageEnd, bool blocking, bool modifiable)
    {
        if (!blocking)
        throw BlockingInputOnly("FilterWithBufferedInput");
        if (length != 0)
        {
            unsigned int newLength = m_queue.CurrentSize() + length;
            if (!m_firstInputDone && newLength >= m_firstSize)
            {
                unsigned int len = m_firstSize - m_queue.CurrentSize();
                m_queue.Put(inString, len);
                FirstPut(m_queue.GetContigousBlocks(m_firstSize));
                assert(m_queue.CurrentSize() == 0);
                m_queue.ResetQueue(m_blockSize, (2 * m_blockSize + m_lastSize - 2) / m_blockSize);
                inString += len;
                newLength -= m_firstSize;
                m_firstInputDone = true;
            }
            if (m_firstInputDone)
            {
                if (m_blockSize == 1)
                {
                    while (newLength > m_lastSize && m_queue.CurrentSize() > 0)
                    {
                        unsigned int len = newLength - m_lastSize;
                        byte * ptr = m_queue.GetContigousBlocks(len);
                        NextPutModifiable(ptr, len);
                        newLength -= len;
                    }
                    if (newLength > m_lastSize)
                    {
                        unsigned int len = newLength - m_lastSize;
                        NextPutMaybeModifiable(inString, len, modifiable);
                        inString += len;
                        newLength -= len;
                    }
                }
                else
                {
                    while (newLength >= m_blockSize + m_lastSize && m_queue.CurrentSize() >= m_blockSize)
                    {
                        NextPutModifiable(m_queue.GetBlock(), m_blockSize);
                        newLength -= m_blockSize;
                    }
                    if (newLength >= m_blockSize + m_lastSize && m_queue.CurrentSize() > 0)
                    {
                        assert(m_queue.CurrentSize() < m_blockSize);
                        unsigned int len = m_blockSize - m_queue.CurrentSize();
                        m_queue.Put(inString, len);
                        inString += len;
                        NextPutModifiable(m_queue.GetBlock(), m_blockSize);
                        newLength -= m_blockSize;
                    }
                    if (newLength >= m_blockSize + m_lastSize)
                    {
                        unsigned int len = RoundDownToMultipleOf(newLength - m_lastSize, m_blockSize);
                        NextPutMaybeModifiable(inString, len, modifiable);
                        inString += len;
                        newLength -= len;
                    }
                }
            }
            m_queue.Put(inString, newLength - m_queue.CurrentSize());
        }
        if (messageEnd)
        {
            if (!m_firstInputDone && m_firstSize == 0)
            FirstPut(NULL);
            SecByteBlock temp(m_queue.CurrentSize());
            m_queue.GetAll(temp);
            LastPut(temp, temp.size());
            m_firstInputDone = false;
            m_queue.ResetQueue(1, m_firstSize);
            Output(1, NULL, 0, messageEnd, blocking);
        }
        return 0;
    }
    void FilterWithBufferedInput::ForceNextPut()
    {
        if (!m_firstInputDone)
        return;
        if (m_blockSize > 1)
        {
            while (m_queue.CurrentSize() >= m_blockSize)
            NextPutModifiable(m_queue.GetBlock(), m_blockSize);
        }
        else
        {
            unsigned int len;
            while ((len = m_queue.CurrentSize()) > 0)
            NextPutModifiable(m_queue.GetContigousBlocks(len), len);
        }
    }
    void FilterWithBufferedInput::NextPutMultiple(const byte * inString, unsigned int length)
    {
        assert(m_blockSize > 1);
        // m_blockSize = 1 should always override this function
        while (length > 0)
        {
            assert(length >= m_blockSize);
            NextPutSingle(inString);
            inString += m_blockSize;
            length -= m_blockSize;
        }
    }
    // *************************************************************
    void Redirector::ChannelInitialize(const std::string & channel, const NameValuePairs & parameters, int propagation)
    {
        if (channel.empty())
        {
            m_target = parameters.GetValueWithDefault("RedirectionTargetPointer", (BufferedTransformation *) NULL);
            m_passSignal = parameters.GetValueWithDefault("PassSignal", true);
        }
        if (m_target && m_passSignal)
        m_target->ChannelInitialize(channel, parameters, propagation);
    }
    // *************************************************************
    ProxyFilter::ProxyFilter(BufferedTransformation * filter, unsigned int firstSize, unsigned int lastSize, BufferedTransformation * attachment)
    : FilterWithBufferedInput(firstSize, 1, lastSize, attachment), m_filter(filter)
    {
        if (m_filter.get())
        m_filter->Attach(new OutputProxy( * this, false));
    }
    bool ProxyFilter::IsolatedFlush(bool hardFlush, bool blocking)
    {
        return m_filter.get() ? m_filter->Flush(hardFlush, - 1, blocking): false;
    }
    void ProxyFilter::SetFilter(Filter * filter)
    {
        m_filter.reset(filter);
        if (filter)
        {
            OutputProxy * proxy;
            std::auto_ptr <OutputProxy > temp(proxy = new OutputProxy( * this, false));
            m_filter->TransferAllTo( * proxy);
            m_filter->Attach(temp.release());
        }
    }
    void ProxyFilter::NextPutMultiple(const byte * s, unsigned int len)
    {
        if (m_filter.get())
        m_filter->Put(s, len);
    }
    // *************************************************************
    unsigned int ArraySink::Put2(const byte * begin, unsigned int length, int messageEnd, bool blocking)
    {
        memcpy(m_buf + m_total, begin, STDMIN(length, SaturatingSubtract(m_size, m_total)));
        m_total += length;
        return 0;
    }
    byte * ArraySink::CreatePutSpace(unsigned int & size)
    {
        size = m_size - m_total;
        return m_buf + m_total;
    }
    void ArraySink::IsolatedInitialize(const NameValuePairs & parameters)
    {
        ByteArrayParameter array;
        if (!parameters.GetValue(Name::OutputBuffer(), array))
        throw InvalidArgument("ArraySink: missing OutputBuffer argument");
        m_buf = array.begin();
        m_size = array.size();
        m_total = 0;
    }
    unsigned int ArrayXorSink::Put2(const byte * begin, unsigned int length, int messageEnd, bool blocking)
    {
        xorbuf(m_buf + m_total, begin, STDMIN(length, SaturatingSubtract(m_size, m_total)));
        m_total += length;
        return 0;
    }
    // *************************************************************
    unsigned int StreamTransformationFilter::LastBlockSize(StreamTransformation & c, BlockPaddingScheme padding)
    {
        if (c.MinLastBlockSize() > 0)
        return c.MinLastBlockSize();
        else if(c.MandatoryBlockSize() > 1 && !c.IsForwardTransformation() && padding != NO_PADDING && padding != ZEROS_PADDING)
        return c.MandatoryBlockSize();
        else
        return 0;
    }
    StreamTransformationFilter::StreamTransformationFilter(StreamTransformation & c, BufferedTransformation * attachment, BlockPaddingScheme padding)
    : FilterWithBufferedInput(0, c.MandatoryBlockSize(), LastBlockSize(c, padding), attachment)
    , m_cipher(c)
    {
        assert(c.MinLastBlockSize() == 0 || c.MinLastBlockSize() > c.MandatoryBlockSize());
        bool isBlockCipher = (c.MandatoryBlockSize() > 1 && c.MinLastBlockSize() == 0);
        if (padding == DEFAULT_PADDING)
        {
            if (isBlockCipher)
            m_padding = PKCS_PADDING;
            else
            m_padding = NO_PADDING;
        }
        else
        m_padding = padding;
        if (!isBlockCipher && (m_padding == PKCS_PADDING || m_padding == ONE_AND_ZEROS_PADDING))
        throw InvalidArgument("StreamTransformationFilter: PKCS_PADDING and ONE_AND_ZEROS_PADDING cannot be used with " + c.AlgorithmName());
    }
    void StreamTransformationFilter::FirstPut(const byte * inString)
    {
        m_optimalBufferSize = m_cipher.OptimalBlockSize();
        m_optimalBufferSize = STDMAX(m_optimalBufferSize, RoundDownToMultipleOf(4096U, m_optimalBufferSize));
    }
    void StreamTransformationFilter::NextPutMultiple(const byte * inString, unsigned int length)
    {
        if (!length)
        return;
        unsigned int s = m_cipher.MandatoryBlockSize();
        do
        {
            unsigned int len = m_optimalBufferSize;
            byte * space = HelpCreatePutSpace( * AttachedTransformation(), NULL_CHANNEL, s, length, len);
            if (len < length)
            {
                if (len == m_optimalBufferSize)
                len -= m_cipher.GetOptimalBlockSizeUsed();
                len = RoundDownToMultipleOf(len, s);
            }
            else
            len = length;
            m_cipher.ProcessString(space, inString, len);
            AttachedTransformation()->PutModifiable(space, len);
            inString += len;
            length -= len;
        }
        while (length > 0);
    }
    void StreamTransformationFilter::NextPutModifiable(byte * inString, unsigned int length)
    {
        m_cipher.ProcessString(inString, length);
        AttachedTransformation()->PutModifiable(inString, length);
    }
    void StreamTransformationFilter::LastPut(const byte * inString, unsigned int length)
    {
        byte * space = NULL;
        switch (m_padding)
        {
        case NO_PADDING:
        case ZEROS_PADDING:
            if (length > 0)
            {
                unsigned int minLastBlockSize = m_cipher.MinLastBlockSize();
                bool isForwardTransformation = m_cipher.IsForwardTransformation();
                if (isForwardTransformation && m_padding == ZEROS_PADDING && (minLastBlockSize == 0 || length < minLastBlockSize))
                {
                    // do padding
                    unsigned int blockSize = STDMAX(minLastBlockSize, m_cipher.MandatoryBlockSize());
                    space = HelpCreatePutSpace( * AttachedTransformation(), NULL_CHANNEL, blockSize);
                    memcpy(space, inString, length);
                    memset(space + length, 0, blockSize - length);
                    m_cipher.ProcessLastBlock(space, space, blockSize);
                    AttachedTransformation()->Put(space, blockSize);
                }
                else
                {
                    if (minLastBlockSize == 0)
                    {
                        if (isForwardTransformation)
                        throw InvalidDataFormat("StreamTransformationFilter: plaintext length is not a multiple of block size and NO_PADDING is specified");
                        else
                        throw InvalidCiphertext("StreamTransformationFilter: ciphertext length is not a multiple of block size");
                    }
                    space = HelpCreatePutSpace( * AttachedTransformation(), NULL_CHANNEL, length, m_optimalBufferSize);
                    m_cipher.ProcessLastBlock(space, inString, length);
                    AttachedTransformation()->Put(space, length);
                }
            }
            break;
        case PKCS_PADDING:
        case ONE_AND_ZEROS_PADDING:
            unsigned int s;
            s = m_cipher.MandatoryBlockSize();
            assert(s > 1);
            space = HelpCreatePutSpace( * AttachedTransformation(), NULL_CHANNEL, s, m_optimalBufferSize);
            if (m_cipher.IsForwardTransformation())
            {
                assert(length < s);
                memcpy(space, inString, length);
                if (m_padding == PKCS_PADDING)
                {
                    assert(s < 256);
                    byte pad = s - length;
                    memset(space + length, pad, s - length);
                }
                else
                {
                    space[length] = 1;
                    memset(space + length + 1, 0, s - length - 1);
                }
                m_cipher.ProcessData(space, space, s);
                AttachedTransformation()->Put(space, s);
            }
            else
            {
                if (length != s)
                throw InvalidCiphertext("StreamTransformationFilter: ciphertext length is not a multiple of block size");
                m_cipher.ProcessData(space, inString, s);
                if (m_padding == PKCS_PADDING)
                {
                    byte pad = space[s - 1];
                    if (pad < 1 || pad > s || std::find_if(space + s - pad, space + s, std::bind2nd(std::not_equal_to < byte > (), pad)) != space + s)
                    throw InvalidCiphertext("StreamTransformationFilter: invalid PKCS #7 block padding found");
                    length = s - pad;
                }
                else
                {
                    while (length > 1 && space[length - 1] == '\0')
                    --length;
                    if (space[--length] != '\1')
                    throw InvalidCiphertext("StreamTransformationFilter: invalid ones-and-zeros padding found");
                }
                AttachedTransformation()->Put(space, length);
            }
            break;
        default:
            assert(false);
        }
    }
    // *************************************************************
    void HashFilter::IsolatedInitialize(const NameValuePairs & parameters)
    {
        m_putMessage = parameters.GetValueWithDefault(Name::PutMessage(), false);
        m_hashModule.Restart();
    }
    unsigned int HashFilter::Put2(const byte * inString, unsigned int length, int messageEnd, bool blocking)
    {
        FILTER_BEGIN;
        m_hashModule.Update(inString, length);
        if (m_putMessage)
        FILTER_OUTPUT(1, inString, length, 0);
        if (messageEnd)
        {
            {
                unsigned int size, digestSize = m_hashModule.DigestSize();
                m_space = HelpCreatePutSpace( * AttachedTransformation(), NULL_CHANNEL, digestSize, digestSize, size = digestSize);
                m_hashModule.Final(m_space);
            }
            FILTER_OUTPUT(2, m_space, m_hashModule.DigestSize(), messageEnd);
        }
        FILTER_END_NO_MESSAGE_END;
    }
    // *************************************************************
    HashVerificationFilter::HashVerificationFilter(HashTransformation & hm, BufferedTransformation * attachment, word32 flags)
    : FilterWithBufferedInput(attachment)
    , m_hashModule(hm)
    {
        IsolatedInitialize(MakeParameters(Name::HashVerificationFilterFlags(), flags));
    }
    void HashVerificationFilter::InitializeDerivedAndReturnNewSizes(const NameValuePairs & parameters, unsigned int & firstSize, unsigned int & blockSize, unsigned int & lastSize)
    {
        m_flags = parameters.GetValueWithDefault(Name::HashVerificationFilterFlags(), (word32) DEFAULT_FLAGS);
        m_hashModule.Restart();
        unsigned int size = m_hashModule.DigestSize();
        m_verified = false;
        firstSize = m_flags & HASH_AT_BEGIN ? size: 0;
        blockSize = 1;
        lastSize = m_flags & HASH_AT_BEGIN ? 0: size;
    }
    void HashVerificationFilter::FirstPut(const byte * inString)
    {
        if (m_flags & HASH_AT_BEGIN)
        {
            m_expectedHash.New(m_hashModule.DigestSize());
            memcpy(m_expectedHash, inString, m_expectedHash.size());
            if (m_flags & PUT_HASH)
            AttachedTransformation()->Put(inString, m_expectedHash.size());
        }
    }
    void HashVerificationFilter::NextPutMultiple(const byte * inString, unsigned int length)
    {
        m_hashModule.Update(inString, length);
        if (m_flags & PUT_MESSAGE)
        AttachedTransformation()->Put(inString, length);
    }
    void HashVerificationFilter::LastPut(const byte * inString, unsigned int length)
    {
        if (m_flags & HASH_AT_BEGIN)
        {
            assert(length == 0);
            m_verified = m_hashModule.Verify(m_expectedHash);
        }
        else
        {
            m_verified = (length == m_hashModule.DigestSize() && m_hashModule.Verify(inString));
            if (m_flags & PUT_HASH)
            AttachedTransformation()->Put(inString, length);
        }
        if (m_flags & PUT_RESULT)
        AttachedTransformation()->Put(m_verified);
        if ((m_flags & THROW_EXCEPTION) && !m_verified)
        throw HashVerificationFailed();
    }
    // *************************************************************
    void SignerFilter::IsolatedInitialize(const NameValuePairs & parameters)
    {
        m_putMessage = parameters.GetValueWithDefault(Name::PutMessage(), false);
        m_messageAccumulator.reset(m_signer.NewSignatureAccumulator());
    }
    unsigned int SignerFilter::Put2(const byte * inString, unsigned int length, int messageEnd, bool blocking)
    {
        FILTER_BEGIN;
        m_messageAccumulator->Update(inString, length);
        if (m_putMessage)
        FILTER_OUTPUT(1, inString, length, 0);
        if (messageEnd)
        {
            m_buf.New(m_signer.SignatureLength());
            m_signer.Sign(m_rng, m_messageAccumulator.release(), m_buf);
            FILTER_OUTPUT(2, m_buf, m_buf.size(), messageEnd);
            m_messageAccumulator.reset(m_signer.NewSignatureAccumulator());
        }
        FILTER_END_NO_MESSAGE_END;
    }
    SignatureVerificationFilter::SignatureVerificationFilter(const PK_Verifier & verifier, BufferedTransformation * attachment, word32 flags)
    : FilterWithBufferedInput(attachment)
    , m_verifier(verifier)
    {
        IsolatedInitialize(MakeParameters(Name::SignatureVerificationFilterFlags(), flags));
    }
    void SignatureVerificationFilter::InitializeDerivedAndReturnNewSizes(const NameValuePairs & parameters, unsigned int & firstSize, unsigned int & blockSize, unsigned int & lastSize)
    {
        m_flags = parameters.GetValueWithDefault(Name::SignatureVerificationFilterFlags(), (word32) DEFAULT_FLAGS);
        m_messageAccumulator.reset(m_verifier.NewVerificationAccumulator());
        unsigned int size = m_verifier.SignatureLength();
        assert(size != 0);
        // TODO: handle recoverable signature scheme
        m_verified = false;
        firstSize = m_flags & SIGNATURE_AT_BEGIN ? size: 0;
        blockSize = 1;
        lastSize = m_flags & SIGNATURE_AT_BEGIN ? 0: size;
    }
    void SignatureVerificationFilter::FirstPut(const byte * inString)
    {
        if (m_flags & SIGNATURE_AT_BEGIN)
        {
            if (m_verifier.SignatureUpfront())
            m_verifier.InputSignature( * m_messageAccumulator, inString, m_verifier.SignatureLength());
            else
            {
                m_signature.New(m_verifier.SignatureLength());
                memcpy(m_signature, inString, m_signature.size());
            }
            if (m_flags & PUT_SIGNATURE)
            AttachedTransformation()->Put(inString, m_signature.size());
        }
        else
        {
            assert(!m_verifier.SignatureUpfront());
        }
    }
    void SignatureVerificationFilter::NextPutMultiple(const byte * inString, unsigned int length)
    {
        m_messageAccumulator->Update(inString, length);
        if (m_flags & PUT_MESSAGE)
        AttachedTransformation()->Put(inString, length);
    }
    void SignatureVerificationFilter::LastPut(const byte * inString, unsigned int length)
    {
        if (m_flags & SIGNATURE_AT_BEGIN)
        {
            assert(length == 0);
            m_verifier.InputSignature( * m_messageAccumulator, m_signature, m_signature.size());
            m_verified = m_verifier.VerifyAndRestart( * m_messageAccumulator);
        }
        else
        {
            m_verifier.InputSignature( * m_messageAccumulator, inString, length);
            m_verified = m_verifier.VerifyAndRestart( * m_messageAccumulator);
            if (m_flags & PUT_SIGNATURE)
            AttachedTransformation()->Put(inString, length);
        }
        if (m_flags & PUT_RESULT)
        AttachedTransformation()->Put(m_verified);
        if ((m_flags & THROW_EXCEPTION) && !m_verified)
        throw SignatureVerificationFailed();
    }
    // *************************************************************
    unsigned int Source::PumpAll2(bool blocking)
    {
        // TODO: switch length type
        unsigned long i = UINT_MAX;
        RETURN_IF_NONZERO(Pump2(i, blocking));
        unsigned int j = UINT_MAX;
        return PumpMessages2(j, blocking);
    }
    bool Store::GetNextMessage()
    {
        if (!m_messageEnd && !AnyRetrievable())
        {
            m_messageEnd = true;
            return true;
        }
        else
        return false;
    }
    unsigned int Store::CopyMessagesTo(BufferedTransformation & target, unsigned int count, const std::string & channel) const
    {
        if (m_messageEnd || count == 0)
        return 0;
        else
        {
            CopyTo(target, ULONG_MAX, channel);
            if (GetAutoSignalPropagation())
            target.ChannelMessageEnd(channel, GetAutoSignalPropagation() - 1);
            return 1;
        }
    }
    void StringStore::StoreInitialize(const NameValuePairs & parameters)
    {
        ConstByteArrayParameter array;
        if (!parameters.GetValue(Name::InputBuffer(), array))
        throw InvalidArgument("StringStore: missing InputBuffer argument");
        m_store = array.begin();
        m_length = array.size();
        m_count = 0;
    }
    unsigned int StringStore::TransferTo2(BufferedTransformation & target, unsigned long & transferBytes, const std::string & channel, bool blocking)
    {
        unsigned long position = 0;
        unsigned int blockedBytes = CopyRangeTo2(target, position, transferBytes, channel, blocking);
        m_count += position;
        transferBytes = position;
        return blockedBytes;
    }
    unsigned int StringStore::CopyRangeTo2(BufferedTransformation & target, unsigned long & begin, unsigned long end, const std::string & channel, bool blocking) const
    {
        unsigned int i = (unsigned int) STDMIN((unsigned long) m_count + begin, (unsigned long) m_length);
        unsigned int len = (unsigned int) STDMIN((unsigned long) m_length - i, end - begin);
        unsigned int blockedBytes = target.ChannelPut2(channel, m_store + i, len, 0, blocking);
        if (!blockedBytes)
        begin += len;
        return blockedBytes;
    }
    unsigned int RandomNumberStore::TransferTo2(BufferedTransformation & target, unsigned long & transferBytes, const std::string & channel, bool blocking)
    {
        if (!blocking)
        throw NotImplemented("RandomNumberStore: nonblocking transfer is not implemented by this object");
        unsigned long transferMax = transferBytes;
        for (transferBytes = 0 ; transferBytes < transferMax && m_count < m_length ;++transferBytes,++m_count)
        target.ChannelPut(channel, m_rng.GenerateByte());
        return 0;
    }
    unsigned int NullStore::CopyRangeTo2(BufferedTransformation & target, unsigned long & begin, unsigned long end, const std::string & channel, bool blocking) const
    {
        static const byte nullBytes[128] =
        {
            0
                };
        while (begin < end)
        {
            unsigned int len = STDMIN(end - begin, 128UL);
            unsigned int blockedBytes = target.ChannelPut2(channel, nullBytes, len, 0, blocking);
            if (blockedBytes)
            return blockedBytes;
            begin += len;
        }
        return 0;
    }
    unsigned int NullStore::TransferTo2(BufferedTransformation & target, unsigned long & transferBytes, const std::string & channel, bool blocking)
    {
        unsigned long begin = 0;
        unsigned int blockedBytes = NullStore::CopyRangeTo2(target, begin, transferBytes, channel, blocking);
        transferBytes = begin;
        m_size -= begin;
        return blockedBytes;
    }
    // fips140.cpp - written and placed in the public domain by Wei Dai
    // Define this to 1 to turn on FIPS 140-2 compliance features, including additional tests during
    // startup, random number generation, and key generation. These tests may affect performance.
#ifndef CRYPTOPP_ENABLE_COMPLIANCE_WITH_FIPS_140_2
#define CRYPTOPP_ENABLE_COMPLIANCE_WITH_FIPS_140_2 0
#endif
#if (CRYPTOPP_ENABLE_COMPLIANCE_WITH_FIPS_140_2 && !defined(THREADS_AVAILABLE))
#error FIPS 140-2 compliance requires the availability of thread local storage.
#endif
    PowerUpSelfTestStatus g_powerUpSelfTestStatus = POWER_UP_SELF_TEST_NOT_DONE;
    bool FIPS_140_2_ComplianceEnabled()
    {
        return CRYPTOPP_ENABLE_COMPLIANCE_WITH_FIPS_140_2;
    }
    void SimulatePowerUpSelfTestFailure()
    {
        g_powerUpSelfTestStatus = POWER_UP_SELF_TEST_FAILED;
    }
    PowerUpSelfTestStatus GetPowerUpSelfTestStatus()
    {
        return g_powerUpSelfTestStatus;
    }
#if CRYPTOPP_ENABLE_COMPLIANCE_WITH_FIPS_140_2
    ThreadLocalStorage & AccessPowerUpSelfTestInProgress()
    {
        static ThreadLocalStorage selfTestInProgress;
        return selfTestInProgress;
    }
#endif
    bool PowerUpSelfTestInProgressOnThisThread()
    {
#if CRYPTOPP_ENABLE_COMPLIANCE_WITH_FIPS_140_2
        return AccessPowerUpSelfTestInProgress() .GetValue() != NULL;
#else
        assert(false);
        // should not be called
        return false;
#endif
    }
    void SetPowerUpSelfTestInProgressOnThisThread(bool inProgress)
    {
#if CRYPTOPP_ENABLE_COMPLIANCE_WITH_FIPS_140_2
        AccessPowerUpSelfTestInProgress() .SetValue((void *) inProgress);
#endif
    }
    void EncryptionPairwiseConsistencyTest_FIPS_140_Only(const PK_Encryptor & encryptor, const PK_Decryptor & decryptor)
    {
#if CRYPTOPP_ENABLE_COMPLIANCE_WITH_FIPS_140_2
        EncryptionPairwiseConsistencyTest(encryptor, decryptor);
#endif
    }
    void SignaturePairwiseConsistencyTest_FIPS_140_Only(const PK_Signer & signer, const PK_Verifier & verifier)
    {
#if CRYPTOPP_ENABLE_COMPLIANCE_WITH_FIPS_140_2
        SignaturePairwiseConsistencyTest(signer, verifier);
#endif
    }
    // integer.cpp - written and placed in the public domain by Wei Dai
    // contains public domain code contributed by Alister Lee and Leonard Janke
    bool FunctionAssignIntToInteger(const std::type_info & valueType, void * pInteger, const void * pInt)
    {
        if (valueType != typeid(Integer))
        return false;
        * reinterpret_cast <Integer *> (pInteger) = * reinterpret_cast <const int *> (pInt);
        return true;
    }
    static int DummyAssignIntToInteger = (AssignIntToInteger = FunctionAssignIntToInteger, 0);
#ifdef SSE2_INTRINSICS_AVAILABLE
    template <class T >
    AllocatorBase <T >::pointer AlignedAllocator <T >::allocate(size_type n, const void *)
    {
        if (n < 4)
        return new T[n];
        else
        return(T *) _mm_malloc(sizeof(T) * n, 16);
    }
    template <class T >
    void AlignedAllocator <T >::deallocate(void * p, size_type n)
    {
        memset(p, 0, n * sizeof(T));
        if (n < 4)
        delete [] p;
        else
        _mm_free(p);
    }
    template class AlignedAllocator <word >;
#endif
#define MAKE_DWORD(lowWord, highWord) ((dword(highWord)<<WORD_BITS) | (lowWord))
    static int Compare(const word * A, const word * B, unsigned int N)
    {
        while (N--)
        if (A[N] > B[N])
        return 1;
        else if(A[N] < B[N])
        return - 1;
        return 0;
    }
    static word Increment(word * A, unsigned int N, word B = 1)
    {
        assert(N);
        word t = A[0];
        A[0] = t + B;
        if (A[0] >= t)
        return 0;
        for (unsigned i = 1 ; i < N ; i++)
        if (++A[i])
        return 0;
        return 1;
    }
    static word Decrement(word * A, unsigned int N, word B = 1)
    {
        assert(N);
        word t = A[0];
        A[0] = t - B;
        if (A[0] <= t)
        return 0;
        for (unsigned i = 1 ; i < N ; i++)
        if (A[i]--)
        return 0;
        return 1;
    }
    static void TwosComplement(word * A, unsigned int N)
    {
        Decrement(A, N);
        for (unsigned i = 0 ; i < N ; i++)
        A[i] = ~ A[i];
    }
    static word LinearMultiply(word * C, const word * A, word B, unsigned int N)
    {
        word carry = 0;
        for (unsigned i = 0 ; i < N ; i++)
        {
            dword p = (dword) A[i] * B + carry;
            C[i] = LOW_WORD(p);
            carry = HIGH_WORD(p);
        }
        return carry;
    }
    static void AtomicInverseModPower2(word * C, word A0, word A1)
    {
        assert(A0% 2 == 1);
        dword A = MAKE_DWORD(A0, A1), R = A0% 8;
        for (unsigned i = 3 ; i < 2 * WORD_BITS ; i *= 2)
        R = R * (2 - R * A);
        assert(R * A == 1);
        C[0] = LOW_WORD(R);
        C[1] = HIGH_WORD(R);
    }
    // ********************************************************
    class Portable
    {
        public:
        static word Add(word * C, const word * A, const word * B, unsigned int N);
        static word Subtract(word * C, const word * A, const word * B, unsigned int N);
        static inline void Multiply2(word * C, const word * A, const word * B);
        static inline word Multiply2Add(word * C, const word * A, const word * B);
        static void Multiply4(word * C, const word * A, const word * B);
        static void Multiply8(word * C, const word * A, const word * B);
        static inline unsigned int MultiplyRecursionLimit()
        {
            return 8;
        }
        static inline void Multiply2Bottom(word * C, const word * A, const word * B);
        static void Multiply4Bottom(word * C, const word * A, const word * B);
        static void Multiply8Bottom(word * C, const word * A, const word * B);
        static inline unsigned int MultiplyBottomRecursionLimit()
        {
            return 8;
        }
        static void Square2(word * R, const word * A);
        static void Square4(word * R, const word * A);
        static void Square8(word * R, const word * A)
        {
            assert(false);
        }
        static inline unsigned int SquareRecursionLimit()
        {
            return 4;
        }
        };
    word Portable::Add(word * C, const word * A, const word * B, unsigned int N)
    {
        assert(N% 2 == 0);
#ifdef IS_LITTLE_ENDIAN
        // dword is only register size:
        if (sizeof(dword) == sizeof(size_t))
        {
            dword carry = 0;
            N >>= 1;
            for (unsigned int i = 0 ; i < N ; i++)
            {
                dword a = ((const dword *) A) [i] + carry;
                dword c = a + ((const dword *) B) [i];
                ((dword *) C) [i] = c;
                carry = (a < carry) | (c < a);
            }
            return(word) carry;
        }
        else
#endif
        {
            word carry = 0;
            for (unsigned int i = 0 ; i < N ; i += 2)
            {
                dword u = (dword) carry + A[i] + B[i];
                C[i] = LOW_WORD(u);
                u = (dword) HIGH_WORD(u) + A[i + 1] + B[i + 1];
                C[i + 1] = LOW_WORD(u);
                carry = HIGH_WORD(u);
            }
            return carry;
        }
    }
    word Portable::Subtract(word * C, const word * A, const word * B, unsigned int N)
    {
        assert(N% 2 == 0);
#ifdef IS_LITTLE_ENDIAN
        // dword is only register size:
        if (sizeof(dword) == sizeof(size_t))
        {
            dword borrow = 0;
            N >>= 1;
            for (unsigned int i = 0 ; i < N ; i++)
            {
                dword a = ((const dword *) A) [i];
                dword b = a - borrow;
                dword c = b - ((const dword *) B) [i];
                ((dword *) C) [i] = c;
                borrow = (b > a) | (c > b);
            }
            return(word) borrow;
        }
        else
#endif
        {
            word borrow = 0;
            for (unsigned i = 0 ; i < N ; i += 2)
            {
                dword u = (dword) A[i] - B[i] - borrow;
                C[i] = LOW_WORD(u);
                u = (dword) A[i + 1] - B[i + 1] - (word)(0 - HIGH_WORD(u));
                C[i + 1] = LOW_WORD(u);
                borrow = 0 - HIGH_WORD(u);
            }
            return borrow;
        }
    }
    void Portable::Multiply2(word * C, const word * A, const word * B)
    {
 /*
 word s;
 dword d;
 if (A1 >= A0)
 if (B0 >= B1)
 {
 s = 0;
 d = (dword)(A1-A0)*(B0-B1);
 }
 else
 {
 s = (A1-A0);
 d = (dword)s*(word)(B0-B1);
 }
 else
 if (B0 > B1)
 {
 s = (B0-B1);
 d = (word)(A1-A0)*(dword)s;
 }
 else
 {
 s = 0;
 d = (dword)(A0-A1)*(B1-B0);
 }
    */
        // this segment is the branchless equivalent of above
        word D[4] =
        {
            A[1] - A[0], A[0] - A[1], B[0] - B[1], B[1] - B[0]
        }
        ;
        unsigned int ai = A[1] <A[0];
        unsigned int bi = B[0] <B[1];
        unsigned int di = ai & bi;
        dword d = (dword) D[di] * D[di + 2];
        D[1] = D[3] = 0;
        unsigned int si = ai + !bi;
        word s = D[si];
        dword A0B0 = (dword) A[0] * B[0];
        C[0] = LOW_WORD(A0B0);
        dword A1B1 = (dword) A[1] * B[1];
        dword t = (dword) HIGH_WORD(A0B0) + LOW_WORD(A0B0) + LOW_WORD(d) + LOW_WORD(A1B1);
        C[1] = LOW_WORD(t);
        t = A1B1 + HIGH_WORD(t) + HIGH_WORD(A0B0) + HIGH_WORD(d) + HIGH_WORD(A1B1) - s;
        C[2] = LOW_WORD(t);
        C[3] = HIGH_WORD(t);
    }
    inline void Portable::Multiply2Bottom(word * C, const word * A, const word * B)
    {
#ifdef IS_LITTLE_ENDIAN
        if (sizeof(dword) == sizeof(size_t))
        {
            dword a = * (const dword *) A, b = * (const dword *) B;
            ((dword *) C) [0] = a * b;
        }
        else
#endif
        {
            dword t = (dword) A[0] * B[0];
            C[0] = LOW_WORD(t);
            C[1] = HIGH_WORD(t) + A[0] * B[1] + A[1] * B[0];
        }
    }
    word Portable::Multiply2Add(word * C, const word * A, const word * B)
    {
        word D[4] =
        {
            A[1] - A[0], A[0] - A[1], B[0] - B[1], B[1] - B[0]
                };
        unsigned int ai = A[1] <A[0];
        unsigned int bi = B[0] <B[1];
        unsigned int di = ai & bi;
        dword d = (dword) D[di] * D[di + 2];
        D[1] = D[3] = 0;
        unsigned int si = ai + !bi;
        word s = D[si];
        dword A0B0 = (dword) A[0] * B[0];
        dword t = A0B0 + C[0];
        C[0] = LOW_WORD(t);
        dword A1B1 = (dword) A[1] * B[1];
        t = (dword) HIGH_WORD(t) + LOW_WORD(A0B0) + LOW_WORD(d) + LOW_WORD(A1B1) + C[1];
        C[1] = LOW_WORD(t);
        t = (dword) HIGH_WORD(t) + LOW_WORD(A1B1) + HIGH_WORD(A0B0) + HIGH_WORD(d) + HIGH_WORD(A1B1) - s + C[2];
        C[2] = LOW_WORD(t);
        t = (dword) HIGH_WORD(t) + HIGH_WORD(A1B1) + C[3];
        C[3] = LOW_WORD(t);
        return HIGH_WORD(t);
    }
#define MulAcc(x, y)								\
    p = (dword) A[x] * B[y] + c;\
    c = LOW_WORD(p);\
    p = (dword) d + HIGH_WORD(p);\
    d = LOW_WORD(p);\
    e += HIGH_WORD(p);
#define SaveMulAcc(s, x, y) 						\
    R[s] = c;\
    p = (dword) A[x] * B[y] + d;\
    c = LOW_WORD(p);\
    p = (dword) e + HIGH_WORD(p);\
    d = LOW_WORD(p);\
    e = HIGH_WORD(p);
#define SquAcc(x, y)								\
    q = (dword) A[x] * A[y];\
    p = q + c;\
    c = LOW_WORD(p);\
    p = (dword) d + HIGH_WORD(p);\
    d = LOW_WORD(p);\
    e += HIGH_WORD(p);\
    p = q + c;\
    c = LOW_WORD(p);\
    p = (dword) d + HIGH_WORD(p);\
    d = LOW_WORD(p);\
    e += HIGH_WORD(p);
#define SaveSquAcc(s, x, y) 						\
    R[s] = c;\
    q = (dword) A[x] * A[y];\
    p = q + d;\
    c = LOW_WORD(p);\
    p = (dword) e + HIGH_WORD(p);\
    d = LOW_WORD(p);\
    e = HIGH_WORD(p);\
    p = q + c;\
    c = LOW_WORD(p);\
    p = (dword) d + HIGH_WORD(p);\
    d = LOW_WORD(p);\
    e += HIGH_WORD(p);
    void Portable::Multiply4(word * R, const word * A, const word * B)
    {
        dword p;
        word c, d, e;
        p = (dword) A[0] * B[0];
        R[0] = LOW_WORD(p);
        c = HIGH_WORD(p);
        d = e = 0;
        MulAcc(0, 1);
        MulAcc(1, 0);
        SaveMulAcc(1, 2, 0);
        MulAcc(1, 1);
        MulAcc(0, 2);
        SaveMulAcc(2, 0, 3);
        MulAcc(1, 2);
        MulAcc(2, 1);
        MulAcc(3, 0);
        SaveMulAcc(3, 3, 1);
        MulAcc(2, 2);
        MulAcc(1, 3);
        SaveMulAcc(4, 2, 3);
        MulAcc(3, 2);
        R[5] = c;
        p = (dword) A[3] * B[3] + d;
        R[6] = LOW_WORD(p);
        R[7] = e + HIGH_WORD(p);
    }
    void Portable::Square2(word * R, const word * A)
    {
        dword p, q;
        word c, d, e;
        p = (dword) A[0] * A[0];
        R[0] = LOW_WORD(p);
        c = HIGH_WORD(p);
        d = e = 0;
        SquAcc(0, 1);
        R[1] = c;
        p = (dword) A[1] * A[1] + d;
        R[2] = LOW_WORD(p);
        R[3] = e + HIGH_WORD(p);
    }
    void Portable::Square4(word * R, const word * A)
    {
        const word * B = A;
        dword p, q;
        word c, d, e;
        p = (dword) A[0] * A[0];
        R[0] = LOW_WORD(p);
        c = HIGH_WORD(p);
        d = e = 0;
        SquAcc(0, 1);
        SaveSquAcc(1, 2, 0);
        MulAcc(1, 1);
        SaveSquAcc(2, 0, 3);
        SquAcc(1, 2);
        SaveSquAcc(3, 3, 1);
        MulAcc(2, 2);
        SaveSquAcc(4, 2, 3);
        R[5] = c;
        p = (dword) A[3] * A[3] + d;
        R[6] = LOW_WORD(p);
        R[7] = e + HIGH_WORD(p);
    }
    void Portable::Multiply8(word * R, const word * A, const word * B)
    {
        dword p;
        word c, d, e;
        p = (dword) A[0] * B[0];
        R[0] = LOW_WORD(p);
        c = HIGH_WORD(p);
        d = e = 0;
        MulAcc(0, 1);
        MulAcc(1, 0);
        SaveMulAcc(1, 2, 0);
        MulAcc(1, 1);
        MulAcc(0, 2);
        SaveMulAcc(2, 0, 3);
        MulAcc(1, 2);
        MulAcc(2, 1);
        MulAcc(3, 0);
        SaveMulAcc(3, 0, 4);
        MulAcc(1, 3);
        MulAcc(2, 2);
        MulAcc(3, 1);
        MulAcc(4, 0);
        SaveMulAcc(4, 0, 5);
        MulAcc(1, 4);
        MulAcc(2, 3);
        MulAcc(3, 2);
        MulAcc(4, 1);
        MulAcc(5, 0);
        SaveMulAcc(5, 0, 6);
        MulAcc(1, 5);
        MulAcc(2, 4);
        MulAcc(3, 3);
        MulAcc(4, 2);
        MulAcc(5, 1);
        MulAcc(6, 0);
        SaveMulAcc(6, 0, 7);
        MulAcc(1, 6);
        MulAcc(2, 5);
        MulAcc(3, 4);
        MulAcc(4, 3);
        MulAcc(5, 2);
        MulAcc(6, 1);
        MulAcc(7, 0);
        SaveMulAcc(7, 1, 7);
        MulAcc(2, 6);
        MulAcc(3, 5);
        MulAcc(4, 4);
        MulAcc(5, 3);
        MulAcc(6, 2);
        MulAcc(7, 1);
        SaveMulAcc(8, 2, 7);
        MulAcc(3, 6);
        MulAcc(4, 5);
        MulAcc(5, 4);
        MulAcc(6, 3);
        MulAcc(7, 2);
        SaveMulAcc(9, 3, 7);
        MulAcc(4, 6);
        MulAcc(5, 5);
        MulAcc(6, 4);
        MulAcc(7, 3);
        SaveMulAcc(10, 4, 7);
        MulAcc(5, 6);
        MulAcc(6, 5);
        MulAcc(7, 4);
        SaveMulAcc(11, 5, 7);
        MulAcc(6, 6);
        MulAcc(7, 5);
        SaveMulAcc(12, 6, 7);
        MulAcc(7, 6);
        R[13] = c;
        p = (dword) A[7] * B[7] + d;
        R[14] = LOW_WORD(p);
        R[15] = e + HIGH_WORD(p);
    }
    void Portable::Multiply4Bottom(word * R, const word * A, const word * B)
    {
        dword p;
        word c, d, e;
        p = (dword) A[0] * B[0];
        R[0] = LOW_WORD(p);
        c = HIGH_WORD(p);
        d = e = 0;
        MulAcc(0, 1);
        MulAcc(1, 0);
        SaveMulAcc(1, 2, 0);
        MulAcc(1, 1);
        MulAcc(0, 2);
        R[2] = c;
        R[3] = d + A[0] * B[3] + A[1] * B[2] + A[2] * B[1] + A[3] * B[0];
    }
    void Portable::Multiply8Bottom(word * R, const word * A, const word * B)
    {
        dword p;
        word c, d, e;
        p = (dword) A[0] * B[0];
        R[0] = LOW_WORD(p);
        c = HIGH_WORD(p);
        d = e = 0;
        MulAcc(0, 1);
        MulAcc(1, 0);
        SaveMulAcc(1, 2, 0);
        MulAcc(1, 1);
        MulAcc(0, 2);
        SaveMulAcc(2, 0, 3);
        MulAcc(1, 2);
        MulAcc(2, 1);
        MulAcc(3, 0);
        SaveMulAcc(3, 0, 4);
        MulAcc(1, 3);
        MulAcc(2, 2);
        MulAcc(3, 1);
        MulAcc(4, 0);
        SaveMulAcc(4, 0, 5);
        MulAcc(1, 4);
        MulAcc(2, 3);
        MulAcc(3, 2);
        MulAcc(4, 1);
        MulAcc(5, 0);
        SaveMulAcc(5, 0, 6);
        MulAcc(1, 5);
        MulAcc(2, 4);
        MulAcc(3, 3);
        MulAcc(4, 2);
        MulAcc(5, 1);
        MulAcc(6, 0);
        R[6] = c;
        R[7] = d + A[0] * B[7] + A[1] * B[6] + A[2] * B[5] + A[3] * B[4] +
        A[4] * B[3] + A[5] * B[2] + A[6] * B[1] + A[7] * B[0];
    }
#undef MulAcc
#undef SaveMulAcc
#undef SquAcc
#undef SaveSquAcc
#if defined(__GNUC__) && defined(__i386__)
    class PentiumOptimized: public Portable
    {
        public:
#ifndef __pic__		// -fpic uses up a register, leaving too few for the asm code
        static word Add(word * C, const word * A, const word * B, unsigned int N);
        static word Subtract(word * C, const word * A, const word * B, unsigned int N);
#endif
        static void Square4(word * R, const word * A);
        static void Multiply4(word * C, const word * A, const word * B);
        static void Multiply8(word * C, const word * A, const word * B);
        };
    typedef PentiumOptimized LowLevel;
    // Add and Subtract assembly code originally contributed by Alister Lee
#ifndef __pic__
    __attribute__((regparm(3))) word PentiumOptimized::Add(word * C, const word * A, const word * B, unsigned int N)
    {
        assert(N% 2 == 0);
        register word carry, temp;
        __asm__ __volatile__(
        "push %%ebp;"
        "sub %3, %2;"
        "xor %0, %0;"
        "sub %4, %0;"
        "lea (%1,%4,4), %1;"
        "sar $1, %0;"
        "jz 1f;"
        "0:;"
        "mov 0(%3), %4;"
        "mov 4(%3), %%ebp;"
        "mov (%1,%0,8), %5;"
        "lea 8(%3), %3;"
        "adc %5, %4;"
        "mov 4(%1,%0,8), %5;"
        "adc %5, %%ebp;"
        "inc %0;"
        "mov %4, -8(%3, %2);"
        "mov %%ebp, -4(%3, %2);"
        "jnz 0b;"
        "1:;"
        "adc $0, %0;"
        "pop %%ebp;"
        : "=aSD" (carry), "+r" (B), "+r" (C), "+r" (A), "+r" (N), "=r" (temp)
        );
        return carry;
    }
    __attribute__((regparm(3))) word PentiumOptimized::Subtract(word * C, const word * A, const word * B, unsigned int N)
    {
        assert(N% 2 == 0);
        register word carry, temp;
        __asm__ __volatile__(
        "push %%ebp;"
        "sub %3, %2;"
        "xor %0, %0;"
        "sub %4, %0;"
        "lea (%1,%4,4), %1;"
        "sar $1, %0;"
        "jz 1f;"
        "0:;"
        "mov 0(%3), %4;"
        "mov 4(%3), %%ebp;"
        "mov (%1,%0,8), %5;"
        "lea 8(%3), %3;"
        "sbb %5, %4;"
        "mov 4(%1,%0,8), %5;"
        "sbb %5, %%ebp;"
        "inc %0;"
        "mov %4, -8(%3, %2);"
        "mov %%ebp, -4(%3, %2);"
        "jnz 0b;"
        "1:;"
        "adc $0, %0;"
        "pop %%ebp;"
        : "=aSD" (carry), "+r" (B), "+r" (C), "+r" (A), "+r" (N), "=r" (temp)
        );
        return carry;
    }
#endif	// __pic__
    // Comba square and multiply assembly code originally contributed by Leonard Janke
#define SqrStartup \
    "push %%ebp\n\t" \
    "push %%esi\n\t" \
    "push %%ebx\n\t" \
    "xor %%ebp, %%ebp\n\t" \
    "xor %%ebx, %%ebx\n\t" \
    "xor %%ecx, %%ecx\n\t"
#define SqrShiftCarry \
    "mov %%ebx, %%ebp\n\t" \
    "mov %%ecx, %%ebx\n\t" \
    "xor %%ecx, %%ecx\n\t"
#define SqrAccumulate(i,j) \
"mov 4*"#j"(%%esi), %%eax\n\t" \
"mull 4*"#i"(%%esi)\n\t" \
    "add %%eax, %%ebp\n\t" \
    "adc %%edx, %%ebx\n\t" \
    "adc %%ch, %%cl\n\t" \
    "add %%eax, %%ebp\n\t" \
    "adc %%edx, %%ebx\n\t" \
    "adc %%ch, %%cl\n\t"
#define SqrAccumulateCentre(i) \
"mov 4*"#i"(%%esi), %%eax\n\t" \
"mull 4*"#i"(%%esi)\n\t" \
    "add %%eax, %%ebp\n\t" \
    "adc %%edx, %%ebx\n\t" \
    "adc %%ch, %%cl\n\t"
#define SqrStoreDigit(X)  \
"mov %%ebp, 4*"#X"(%%edi)\n\t"
#define SqrLastDiagonal(digits) \
"mov 4*("#digits"-1)(%%esi), %%eax\n\t" \
"mull 4*("#digits"-1)(%%esi)\n\t" \
    "add %%eax, %%ebp\n\t" \
    "adc %%edx, %%ebx\n\t" \
"mov %%ebp, 4*(2*"#digits"-2)(%%edi)\n\t" \
"mov %%ebx, 4*(2*"#digits"-1)(%%edi)\n\t"
#define SqrCleanup \
    "pop %%ebx\n\t" \
    "pop %%esi\n\t" \
    "pop %%ebp\n\t"
    void PentiumOptimized::Square4(word * Y, const word * X)
    {
        __asm__ __volatile__(
        SqrStartup
        SqrAccumulateCentre(0)
        SqrStoreDigit(0)
        SqrShiftCarry
        SqrAccumulate(1, 0)
        SqrStoreDigit(1)
        SqrShiftCarry
        SqrAccumulate(2, 0)
        SqrAccumulateCentre(1)
        SqrStoreDigit(2)
        SqrShiftCarry
        SqrAccumulate(3, 0)
        SqrAccumulate(2, 1)
        SqrStoreDigit(3)
        SqrShiftCarry
        SqrAccumulate(3, 1)
        SqrAccumulateCentre(2)
        SqrStoreDigit(4)
        SqrShiftCarry
        SqrAccumulate(3, 2)
        SqrStoreDigit(5)
        SqrShiftCarry
        SqrLastDiagonal(4)
        SqrCleanup
        :
        : "D" (Y), "S" (X)
        : "eax", "ecx", "edx", "memory"
        );
    }
#define MulStartup \
    "push %%ebp\n\t" \
    "push %%esi\n\t" \
    "push %%ebx\n\t" \
    "push %%edi\n\t" \
    "mov %%eax, %%ebx \n\t" \
    "xor %%ebp, %%ebp\n\t" \
    "xor %%edi, %%edi\n\t" \
    "xor %%ecx, %%ecx\n\t"
#define MulShiftCarry \
    "mov %%edx, %%ebp\n\t" \
    "mov %%ecx, %%edi\n\t" \
    "xor %%ecx, %%ecx\n\t"
#define MulAccumulate(i,j) \
"mov 4*"#j"(%%ebx), %%eax\n\t" \
"mull 4*"#i"(%%esi)\n\t" \
    "add %%eax, %%ebp\n\t" \
    "adc %%edx, %%edi\n\t" \
    "adc %%ch, %%cl\n\t"
#define MulStoreDigit(X)  \
    "mov %%edi, %%edx \n\t" \
    "mov (%%esp), %%edi \n\t" \
"mov %%ebp, 4*"#X"(%%edi)\n\t" \
    "mov %%edi, (%%esp)\n\t"
#define MulLastDiagonal(digits) \
"mov 4*("#digits"-1)(%%ebx), %%eax\n\t" \
"mull 4*("#digits"-1)(%%esi)\n\t" \
    "add %%eax, %%ebp\n\t" \
    "adc %%edi, %%edx\n\t" \
    "mov (%%esp), %%edi\n\t" \
"mov %%ebp, 4*(2*"#digits"-2)(%%edi)\n\t" \
"mov %%edx, 4*(2*"#digits"-1)(%%edi)\n\t"
#define MulCleanup \
    "pop %%edi\n\t" \
    "pop %%ebx\n\t" \
    "pop %%esi\n\t" \
    "pop %%ebp\n\t"
    void PentiumOptimized::Multiply4(word * Z, const word * X, const word * Y)
    {
        __asm__ __volatile__(
        MulStartup
        MulAccumulate(0, 0)
        MulStoreDigit(0)
        MulShiftCarry
        MulAccumulate(1, 0)
        MulAccumulate(0, 1)
        MulStoreDigit(1)
        MulShiftCarry
        MulAccumulate(2, 0)
        MulAccumulate(1, 1)
        MulAccumulate(0, 2)
        MulStoreDigit(2)
        MulShiftCarry
        MulAccumulate(3, 0)
        MulAccumulate(2, 1)
        MulAccumulate(1, 2)
        MulAccumulate(0, 3)
        MulStoreDigit(3)
        MulShiftCarry
        MulAccumulate(3, 1)
        MulAccumulate(2, 2)
        MulAccumulate(1, 3)
        MulStoreDigit(4)
        MulShiftCarry
        MulAccumulate(3, 2)
        MulAccumulate(2, 3)
        MulStoreDigit(5)
        MulShiftCarry
        MulLastDiagonal(4)
        MulCleanup
        :
        : "D" (Z), "S" (X), "a" (Y)
        : "%ecx", "%edx", "memory"
        );
    }
    void PentiumOptimized::Multiply8(word * Z, const word * X, const word * Y)
    {
        __asm__ __volatile__(
        MulStartup
        MulAccumulate(0, 0)
        MulStoreDigit(0)
        MulShiftCarry
        MulAccumulate(1, 0)
        MulAccumulate(0, 1)
        MulStoreDigit(1)
        MulShiftCarry
        MulAccumulate(2, 0)
        MulAccumulate(1, 1)
        MulAccumulate(0, 2)
        MulStoreDigit(2)
        MulShiftCarry
        MulAccumulate(3, 0)
        MulAccumulate(2, 1)
        MulAccumulate(1, 2)
        MulAccumulate(0, 3)
        MulStoreDigit(3)
        MulShiftCarry
        MulAccumulate(4, 0)
        MulAccumulate(3, 1)
        MulAccumulate(2, 2)
        MulAccumulate(1, 3)
        MulAccumulate(0, 4)
        MulStoreDigit(4)
        MulShiftCarry
        MulAccumulate(5, 0)
        MulAccumulate(4, 1)
        MulAccumulate(3, 2)
        MulAccumulate(2, 3)
        MulAccumulate(1, 4)
        MulAccumulate(0, 5)
        MulStoreDigit(5)
        MulShiftCarry
        MulAccumulate(6, 0)
        MulAccumulate(5, 1)
        MulAccumulate(4, 2)
        MulAccumulate(3, 3)
        MulAccumulate(2, 4)
        MulAccumulate(1, 5)
        MulAccumulate(0, 6)
        MulStoreDigit(6)
        MulShiftCarry
        MulAccumulate(7, 0)
        MulAccumulate(6, 1)
        MulAccumulate(5, 2)
        MulAccumulate(4, 3)
        MulAccumulate(3, 4)
        MulAccumulate(2, 5)
        MulAccumulate(1, 6)
        MulAccumulate(0, 7)
        MulStoreDigit(7)
        MulShiftCarry
        MulAccumulate(7, 1)
        MulAccumulate(6, 2)
        MulAccumulate(5, 3)
        MulAccumulate(4, 4)
        MulAccumulate(3, 5)
        MulAccumulate(2, 6)
        MulAccumulate(1, 7)
        MulStoreDigit(8)
        MulShiftCarry
        MulAccumulate(7, 2)
        MulAccumulate(6, 3)
        MulAccumulate(5, 4)
        MulAccumulate(4, 5)
        MulAccumulate(3, 6)
        MulAccumulate(2, 7)
        MulStoreDigit(9)
        MulShiftCarry
        MulAccumulate(7, 3)
        MulAccumulate(6, 4)
        MulAccumulate(5, 5)
        MulAccumulate(4, 6)
        MulAccumulate(3, 7)
        MulStoreDigit(10)
        MulShiftCarry
        MulAccumulate(7, 4)
        MulAccumulate(6, 5)
        MulAccumulate(5, 6)
        MulAccumulate(4, 7)
        MulStoreDigit(11)
        MulShiftCarry
        MulAccumulate(7, 5)
        MulAccumulate(6, 6)
        MulAccumulate(5, 7)
        MulStoreDigit(12)
        MulShiftCarry
        MulAccumulate(7, 6)
        MulAccumulate(6, 7)
        MulStoreDigit(13)
        MulShiftCarry
        MulLastDiagonal(8)
        MulCleanup
        :
        : "D" (Z), "S" (X), "a" (Y)
        : "%ecx", "%edx", "memory"
        );
    }
#elif defined(__GNUC__) && defined(__alpha__)
    class AlphaOptimized: public Portable
    {
        public:
        static inline void Multiply2(word * C, const word * A, const word * B);
        static inline word Multiply2Add(word * C, const word * A, const word * B);
        static inline void Multiply4(word * C, const word * A, const word * B);
        static inline unsigned int MultiplyRecursionLimit()
        {
            return 4;
        }
        static inline void Multiply4Bottom(word * C, const word * A, const word * B);
        static inline unsigned int MultiplyBottomRecursionLimit()
        {
            return 4;
        }
        static inline void Square4(word * R, const word * A)
        {
            Multiply4(R, A, A);
        }
        };
    typedef AlphaOptimized LowLevel;
    inline void AlphaOptimized::Multiply2(word * C, const word * A, const word * B)
    {
        register dword c, a = * (const dword *) A, b = * (const dword *) B;
        ((dword *) C) [0] = a * b;
        __asm__("umulh %1,%2,%0": "=r" (c): "r" (a), "r" (b));
        ((dword *) C) [1] = c;
    }
    inline word AlphaOptimized::Multiply2Add(word * C, const word * A, const word * B)
    {
        register dword c, d, e, a = * (const dword *) A, b = * (const dword *) B;
        c = ((dword *) C) [0];
        d = a * b + c;
        __asm__("umulh %1,%2,%0": "=r" (e): "r" (a), "r" (b));
        ((dword *) C) [0] = d;
        d = (d < c);
        c = ((dword *) C) [1] + d;
        d = (c < d);
        c += e;
        ((dword *) C) [1] = c;
        d |= (c < e);
        return d;
    }
    inline void AlphaOptimized::Multiply4(word * R, const word * A, const word * B)
    {
        Multiply2(R, A, B);
        Multiply2(R + 4, A + 2, B + 2);
        word carry = Multiply2Add(R + 2, A + 0, B + 2);
        carry += Multiply2Add(R + 2, A + 2, B + 0);
        Increment(R + 6, 2, carry);
    }
    static inline void Multiply2BottomAdd(word * C, const word * A, const word * B)
    {
        register dword a = * (const dword *) A, b = * (const dword *) B;
        ((dword *) C) [0] = a * b + ((dword *) C) [0];
    }
    inline void AlphaOptimized::Multiply4Bottom(word * R, const word * A, const word * B)
    {
        Multiply2(R, A, B);
        Multiply2BottomAdd(R + 2, A + 0, B + 2);
        Multiply2BottomAdd(R + 2, A + 2, B + 0);
    }
#else	// no processor specific code available

typedef Portable LowLevel;

#endif

// ********************************************************

#define A0		A
#define A1		(A+N2)
#define B0		B
#define B1		(B+N2)

#define T0		T
#define T1		(T+N2)
#define T2		(T+N)
#define T3		(T+N+N2)

#define R0		R
#define R1		(R+N2)
#define R2		(R+N)
#define R3		(R+N+N2)

//VC60 workaround: compiler bug triggered without the extra dummy parameters

// R[2*N] - result = A*B
// T[2*N] - temporary work space
// A[N] --- multiplier
// B[N] --- multiplicant

template <class P >
void DoRecursiveMultiply(word * R, word * T, const word * A, const word * B, unsigned int N, const P * dummy = NULL);

template <class P >
inline void RecursiveMultiply(word * R, word * T, const word * A, const word * B, unsigned int N, const P * dummy = NULL)
{
    assert(N >= 2 && N% 2 == 0);
    if (P::MultiplyRecursionLimit() >= 8 && N == 8)
    P::Multiply8(R, A, B);
    else if(P::MultiplyRecursionLimit() >= 4 && N == 4)
    P::Multiply4(R, A, B);
    else if(N == 2)
    P::Multiply2(R, A, B);
    else
    DoRecursiveMultiply <P > (R, T, A, B, N, NULL);
    // VC60 workaround: needs this NULL
}

template <class P >
void DoRecursiveMultiply(word * R, word * T, const word * A, const word * B, unsigned int N, const P * dummy)
{
    const unsigned int N2 = N/ 2;
    int carry;
    int aComp = Compare(A0, A1, N2);
    int bComp = Compare(B0, B1, N2);
    switch (2 * aComp + aComp + bComp)
    {
    case - 4:
        P::Subtract(R0, A1, A0, N2);
        P::Subtract(R1, B0, B1, N2);
        RecursiveMultiply <P > (T0, T2, R0, R1, N2);
        P::Subtract(T1, T1, R0, N2);
        carry = - 1;
        break;
    case - 2:
        P::Subtract(R0, A1, A0, N2);
        P::Subtract(R1, B0, B1, N2);
        RecursiveMultiply <P > (T0, T2, R0, R1, N2);
        carry = 0;
        break;
    case 2:
        P::Subtract(R0, A0, A1, N2);
        P::Subtract(R1, B1, B0, N2);
        RecursiveMultiply <P > (T0, T2, R0, R1, N2);
        carry = 0;
        break;
    case 4:
        P::Subtract(R0, A1, A0, N2);
        P::Subtract(R1, B0, B1, N2);
        RecursiveMultiply <P > (T0, T2, R0, R1, N2);
        P::Subtract(T1, T1, R1, N2);
        carry = - 1;
        break;
    default:
        SetWords(T0, 0, N);
        carry = 0;
    }
    RecursiveMultiply <P > (R0, T2, A0, B0, N2);
    RecursiveMultiply <P > (R2, T2, A1, B1, N2);
    // now T[01] holds (A1-A0)*(B0-B1), R[01] holds A0*B0, R[23] holds A1*B1
    carry += P::Add(T0, T0, R0, N);
    carry += P::Add(T0, T0, R2, N);
    carry += P::Add(R1, R1, T0, N);
    assert(carry >= 0 && carry <= 2);
    Increment(R3, N2, carry);
}

// R[2*N] - result = A*A
// T[2*N] - temporary work space
// A[N] --- number to be squared

template <class P >
void DoRecursiveSquare(word * R, word * T, const word * A, unsigned int N, const P * dummy = NULL);

template <class P >
inline void RecursiveSquare(word * R, word * T, const word * A, unsigned int N, const P * dummy = NULL)
{
    assert(N && N% 2 == 0);
    if (P::SquareRecursionLimit() >= 8 && N == 8)
    P::Square8(R, A);
    if (P::SquareRecursionLimit() >= 4 && N == 4)
    P::Square4(R, A);
    else if(N == 2)
    P::Square2(R, A);
    else
    DoRecursiveSquare <P > (R, T, A, N, NULL);
    // VC60 workaround: needs this NULL
}

template <class P >
void DoRecursiveSquare(word * R, word * T, const word * A, unsigned int N, const P * dummy)
{
    const unsigned int N2 = N/ 2;
    RecursiveSquare <P > (R0, T2, A0, N2);
    RecursiveSquare <P > (R2, T2, A1, N2);
    RecursiveMultiply <P > (T0, T2, A0, A1, N2);
    word carry = P::Add(R1, R1, T0, N);
    carry += P::Add(R1, R1, T0, N);
    Increment(R3, N2, carry);
}

// R[N] - bottom half of A*B
// T[N] - temporary work space
// A[N] - multiplier
// B[N] - multiplicant

template <class P >
void DoRecursiveMultiplyBottom(word * R, word * T, const word * A, const word * B, unsigned int N, const P * dummy = NULL);

template <class P >
inline void RecursiveMultiplyBottom(word * R, word * T, const word * A, const word * B, unsigned int N, const P * dummy = NULL)
{
    assert(N >= 2 && N% 2 == 0);
    if (P::MultiplyBottomRecursionLimit() >= 8 && N == 8)
    P::Multiply8Bottom(R, A, B);
    else if(P::MultiplyBottomRecursionLimit() >= 4 && N == 4)
    P::Multiply4Bottom(R, A, B);
    else if(N == 2)
    P::Multiply2Bottom(R, A, B);
    else
    DoRecursiveMultiplyBottom <P > (R, T, A, B, N, NULL);
}

template <class P >
void DoRecursiveMultiplyBottom(word * R, word * T, const word * A, const word * B, unsigned int N, const P * dummy)
{
    const unsigned int N2 = N/ 2;
    RecursiveMultiply <P > (R, T, A0, B0, N2);
    RecursiveMultiplyBottom <P > (T0, T1, A1, B0, N2);
    P::Add(R1, R1, T0, N2);
    RecursiveMultiplyBottom <P > (T0, T1, A0, B1, N2);
    P::Add(R1, R1, T0, N2);
}

// R[N] --- upper half of A*B
// T[2*N] - temporary work space
// L[N] --- lower half of A*B
// A[N] --- multiplier
// B[N] --- multiplicant

template <class P >
void RecursiveMultiplyTop(word * R, word * T, const word * L, const word * A, const word * B, unsigned int N, const P * dummy = NULL)
{
    assert(N >= 2 && N% 2 == 0);
    if (N == 4)
    {
        P::Multiply4(T, A, B);
        ((dword *) R) [0] = ((dword *) T) [2];
        ((dword *) R) [1] = ((dword *) T) [3];
    }
    else if(N == 2)
    {
        P::Multiply2(T, A, B);
        ((dword *) R) [0] = ((dword *) T) [1];
    }
    else
    {
        const unsigned int N2 = N/ 2;
        int carry;
        int aComp = Compare(A0, A1, N2);
        int bComp = Compare(B0, B1, N2);
        switch (2 * aComp + aComp + bComp)
        {
        case - 4:
            P::Subtract(R0, A1, A0, N2);
            P::Subtract(R1, B0, B1, N2);
            RecursiveMultiply <P > (T0, T2, R0, R1, N2);
            P::Subtract(T1, T1, R0, N2);
            carry = - 1;
            break;
        case - 2:
            P::Subtract(R0, A1, A0, N2);
            P::Subtract(R1, B0, B1, N2);
            RecursiveMultiply <P > (T0, T2, R0, R1, N2);
            carry = 0;
            break;
        case 2:
            P::Subtract(R0, A0, A1, N2);
            P::Subtract(R1, B1, B0, N2);
            RecursiveMultiply <P > (T0, T2, R0, R1, N2);
            carry = 0;
            break;
        case 4:
            P::Subtract(R0, A1, A0, N2);
            P::Subtract(R1, B0, B1, N2);
            RecursiveMultiply <P > (T0, T2, R0, R1, N2);
            P::Subtract(T1, T1, R1, N2);
            carry = - 1;
            break;
        default:
            SetWords(T0, 0, N);
            carry = 0;
        }
        RecursiveMultiply <P > (T2, R0, A1, B1, N2);
        // now T[01] holds (A1-A0)*(B0-B1), T[23] holds A1*B1
        word c2 = P::Subtract(R0, L + N2, L, N2);
        c2 += P::Subtract(R0, R0, T0, N2);
        word t = (Compare(R0, T2, N2) == - 1);
        carry += t;
        carry += Increment(R0, N2, c2 + t);
        carry += P::Add(R0, R0, T1, N2);
        carry += P::Add(R0, R0, T3, N2);
        assert(carry >= 0 && carry <= 2);
        CopyWords(R1, T3, N2);
        Increment(R1, N2, carry);
    }
}

inline word Add(word * C, const word * A, const word * B, unsigned int N)
{
    return LowLevel::Add(C, A, B, N);
}

inline word Subtract(word * C, const word * A, const word * B, unsigned int N)
{
    return LowLevel::Subtract(C, A, B, N);
}

inline void Multiply(word * R, word * T, const word * A, const word * B, unsigned int N)
{
#ifdef SSE2_INTRINSICS_AVAILABLE
    if (HasSSE2())
    RecursiveMultiply <P4Optimized > (R, T, A, B, N);
    else
#endif
    RecursiveMultiply <LowLevel > (R, T, A, B, N);
}

inline void Square(word * R, word * T, const word * A, unsigned int N)
{
#ifdef SSE2_INTRINSICS_AVAILABLE
    if (HasSSE2())
    RecursiveSquare <P4Optimized > (R, T, A, N);
    else
#endif
    RecursiveSquare <LowLevel > (R, T, A, N);
}

inline void MultiplyBottom(word * R, word * T, const word * A, const word * B, unsigned int N)
{
#ifdef SSE2_INTRINSICS_AVAILABLE
    if (HasSSE2())
    RecursiveMultiplyBottom <P4Optimized > (R, T, A, B, N);
    else
#endif
    RecursiveMultiplyBottom <LowLevel > (R, T, A, B, N);
}

inline void MultiplyTop(word * R, word * T, const word * L, const word * A, const word * B, unsigned int N)
{
#ifdef SSE2_INTRINSICS_AVAILABLE
    if (HasSSE2())
    RecursiveMultiplyTop <P4Optimized > (R, T, L, A, B, N);
    else
#endif
    RecursiveMultiplyTop <LowLevel > (R, T, L, A, B, N);
}

// R[NA+NB] - result = A*B
// T[NA+NB] - temporary work space
// A[NA] ---- multiplier
// B[NB] ---- multiplicant

void AsymmetricMultiply(word * R, word * T, const word * A, unsigned int NA, const word * B, unsigned int NB)
{
    if (NA == NB)
    {
        if (A == B)
        Square(R, T, A, NA);
        else
        Multiply(R, T, A, B, NA);
        return;
    }
    if (NA > NB)
    {
        std::swap(A, B);
        std::swap(NA, NB);
    }
    assert(NB % NA == 0);
    assert((NB/ NA) % 2 == 0);
    // NB is an even multiple of NA
    if (NA == 2 && !A[1])
    {
        switch (A[0])
        {
        case 0:
            SetWords(R, 0, NB + 2);
            return;
        case 1:
            CopyWords(R, B, NB);
            R[NB] = R[NB + 1] = 0;
            return;
        default:
            R[NB] = LinearMultiply(R, B, A[0], NB);
            R[NB + 1] = 0;
            return;
        }
    }
    Multiply(R, T, A, B, NA);
    CopyWords(T + 2 * NA, R + NA, NA);
    unsigned i;
    for (i = 2 * NA ; i < NB ; i += 2 * NA)
    Multiply(T + NA + i, T, A, B + i, NA);
    for (i = NA ; i < NB ; i += 2 * NA)
    Multiply(R + i, T, A, B + i, NA);
    if (Add(R + NA, R + NA, T + 2 * NA, NB - NA))
    Increment(R + NB, NA);
}

// R[N] ----- result = A inverse mod 2**(WORD_BITS*N)
// T[3*N/2] - temporary work space
// A[N] ----- an odd number as input

void RecursiveInverseModPower2(word * R, word * T, const word * A, unsigned int N)
{
    if (N == 2)
    AtomicInverseModPower2(R, A[0], A[1]);
    else
    {
        const unsigned int N2 = N/ 2;
        RecursiveInverseModPower2(R0, T0, A0, N2);
        T0[0] = 1;
        SetWords(T0 + 1, 0, N2 - 1);
        MultiplyTop(R1, T1, T0, R0, A0, N2);
        MultiplyBottom(T0, T1, R0, A1, N2);
        Add(T0, R1, T0, N2);
        TwosComplement(T0, N2);
        MultiplyBottom(R1, T1, R0, T0, N2);
    }
}

// R[N] --- result = X/(2**(WORD_BITS*N)) mod M
// T[3*N] - temporary work space
// X[2*N] - number to be reduced
// M[N] --- modulus
// U[N] --- multiplicative inverse of M mod 2**(WORD_BITS*N)

void MontgomeryReduce(word * R, word * T, const word * X, const word * M, const word * U, unsigned int N)
{
    MultiplyBottom(R, T, X, U, N);
    MultiplyTop(T, T + N, X, R, M, N);
    word borrow = Subtract(T, X + N, T, N);
    // defend against timing attack by doing this Add even when not needed
    word carry = Add(T + N, T, M, N);
    assert(carry || !borrow);
    CopyWords(R, T + (borrow ? N: 0), N);
}

// R[N] --- result = X/(2**(WORD_BITS*N/2)) mod M
// T[2*N] - temporary work space
// X[2*N] - number to be reduced
// M[N] --- modulus
// U[N/2] - multiplicative inverse of M mod 2**(WORD_BITS*N/2)
// V[N] --- 2**(WORD_BITS*3*N/2) mod M

void HalfMontgomeryReduce(word * R, word * T, const word * X, const word * M, const word * U, const word * V, unsigned int N)
{
    assert(N% 2 == 0 && N >= 4);
#define M0		M
#define M1		(M+N2)
#define V0		V
#define V1		(V+N2)
#define X0		X
#define X1		(X+N2)
#define X2		(X+N)
#define X3		(X+N+N2)
    const unsigned int N2 = N/ 2;
    Multiply(T0, T2, V0, X3, N2);
    int c2 = Add(T0, T0, X0, N);
    MultiplyBottom(T3, T2, T0, U, N2);
    MultiplyTop(T2, R, T0, T3, M0, N2);
    c2 -= Subtract(T2, T1, T2, N2);
    Multiply(T0, R, T3, M1, N2);
    c2 -= Subtract(T0, T2, T0, N2);
    int c3 = - (int) Subtract(T1, X2, T1, N2);
    Multiply(R0, T2, V1, X3, N2);
    c3 += Add(R, R, T, N);
    if (c2 > 0)
    c3 += Increment(R1, N2);
    else if(c2 < 0)
    c3 -= Decrement(R1, N2, - c2);
    assert(c3 >= - 1 && c3 <= 1);
    if (c3 > 0)
    Subtract(R, R, M, N);
    else if(c3 < 0)
    Add(R, R, M, N);
#undef M0
#undef M1
#undef V0
#undef V1
#undef X0
#undef X1
#undef X2
#undef X3
}

#undef A0
#undef A1
#undef B0
#undef B1

#undef T0
#undef T1
#undef T2
#undef T3

#undef R0
#undef R1
#undef R2
#undef R3

// do a 3 word by 2 word divide, returns quotient and leaves remainder in A
static word SubatomicDivide(word * A, word B0, word B1)
{
    // assert {A[2],A[1]} < {B1,B0}, so quotient can fit in a word
    assert(A[2] < B1 || (A[2] == B1 && A[1] < B0));
    dword p, u;
    word Q;
    // estimate the quotient: do a 2 word by 1 word divide
    if (B1 + 1 == 0)
    Q = A[2];
    else
    Q = word(MAKE_DWORD(A[1], A[2]) / (B1 + 1));
    // now subtract Q*B from A
    p = (dword) B0 * Q;
    u = (dword) A[0] - LOW_WORD(p);
    A[0] = LOW_WORD(u);
    u = (dword) A[1] - HIGH_WORD(p) - (word)(0 - HIGH_WORD(u)) - (dword) B1 * Q;
    A[1] = LOW_WORD(u);
    A[2] += HIGH_WORD(u);
    // Q <= actual quotient, so fix it
    while (A[2] || A[1] > B1 || (A[1] == B1 && A[0] >= B0))
    {
        u = (dword) A[0] - B0;
        A[0] = LOW_WORD(u);
        u = (dword) A[1] - B1 - (word)(0 - HIGH_WORD(u));
        A[1] = LOW_WORD(u);
        A[2] += HIGH_WORD(u);
        Q++;
        assert(Q);
        // shouldn't overflow
    }
    return Q;
}

// do a 4 word by 2 word divide, returns 2 word quotient in Q0 and Q1
static inline void AtomicDivide(word * Q, const word * A, const word * B)
{
    // if divisor is 0, we assume divisor==2**(2*WORD_BITS):
    if (!B[0] && !B[1])
    {
        Q[0] = A[2];
        Q[1] = A[3];
    }
    else
    {
        word T[4];
        T[0] = A[0];
        T[1] = A[1];
        T[2] = A[2];
        T[3] = A[3];
        Q[1] = SubatomicDivide(T + 1, B[0], B[1]);
        Q[0] = SubatomicDivide(T, B[0], B[1]);
    }
}

// for use by Divide(), corrects the underestimated quotient {Q1,Q0}
static void CorrectQuotientEstimate(word * R, word * T, word * Q, const word * B, unsigned int N)
{
    assert(N && N% 2 == 0);
    if (Q[1])
    {
        T[N] = T[N + 1] = 0;
        unsigned i;
        for (i = 0 ; i < N ; i += 4)
        LowLevel::Multiply2(T + i, Q, B + i);
        for (i = 2 ; i < N ; i += 4)
        if (LowLevel::Multiply2Add(T + i, Q, B + i))
        T[i + 5] += (++T[i + 4] == 0);
    }
    else
    {
        T[N] = LinearMultiply(T, B, Q[0], N);
        T[N + 1] = 0;
    }
    word borrow = Subtract(R, R, T, N + 2);
    assert(!borrow && !R[N + 1]);
    while (R[N] || Compare(R, B, N) >= 0)
    {
        R[N] -= Subtract(R, R, B, N);
        Q[1] += (++Q[0] == 0);
        assert(Q[0] || Q[1]);
        // no overflow
    }
}

// R[NB] -------- remainder = A%B
// Q[NA-NB+2] --- quotient	= A/B
// T[NA+2*NB+4] - temp work space
// A[NA] -------- dividend
// B[NB] -------- divisor

void Divide(word * R, word * Q, word * T, const word * A, unsigned int NA, const word * B, unsigned int NB)
{
    assert(NA && NB && NA% 2 == 0 && NB% 2 == 0);
    assert(B[NB - 1] || B[NB - 2]);
    assert(NB <= NA);
    // set up temporary work space
    word * const TA = T;
    word * const TB = T + NA + 2;
    word * const TP = T + NA + 2 + NB;
    // copy B into TB and normalize it so that TB has highest bit set to 1
    unsigned shiftWords = (B[NB - 1] == 0);
    TB[0] = TB[NB - 1] = 0;
    CopyWords(TB + shiftWords, B, NB - shiftWords);
    unsigned shiftBits = WORD_BITS - BitPrecision(TB[NB - 1]);
    assert(shiftBits < WORD_BITS);
    ShiftWordsLeftByBits(TB, NB, shiftBits);
    // copy A into TA and normalize it
    TA[0] = TA[NA] = TA[NA + 1] = 0;
    CopyWords(TA + shiftWords, A, NA);
    ShiftWordsLeftByBits(TA, NA + 2, shiftBits);
    if (TA[NA + 1] == 0 && TA[NA] <= 1)
    {
        Q[NA - NB + 1] = Q[NA - NB] = 0;
        while (TA[NA] || Compare(TA + NA - NB, TB, NB) >= 0)
        {
            TA[NA] -= Subtract(TA + NA - NB, TA + NA - NB, TB, NB);
            ++Q[NA - NB];
        }
    }
    else
    {
        NA += 2;
        assert(Compare(TA + NA - NB, TB, NB) < 0);
    }
    word BT[2];
    BT[0] = TB[NB - 2] + 1;
    BT[1] = TB[NB - 1] + (BT[0] == 0);
    // start reducing TA mod TB, 2 words at a time
    for (unsigned i = NA - 2 ; i >= NB ; i -= 2)
    {
        AtomicDivide(Q + i - NB, TA + i - 2, BT);
        CorrectQuotientEstimate(TA + i - NB, TP, Q + i - NB, TB, NB);
    }
    // copy TA into R, and denormalize it
    CopyWords(R, TA + shiftWords, NB);
    ShiftWordsRightByBits(R, NB, shiftBits);
}

static inline unsigned int EvenWordCount(const word * X, unsigned int N)
{
    while (N && X[N - 2] == 0 && X[N - 1] == 0)
    N -= 2;
    return N;
}

// return k
// R[N] --- result = A^(-1) * 2^k mod M
// T[4*N] - temporary work space
// A[NA] -- number to take inverse of
// M[N] --- modulus

unsigned int AlmostInverse(word * R, word * T, const word * A, unsigned int NA, const word * M, unsigned int N)
{
    assert(NA <= N && N && N% 2 == 0);
    word * b = T;
    word * c = T + N;
    word * f = T + 2 * N;
    word * g = T + 3 * N;
    unsigned int bcLen = 2, fgLen = EvenWordCount(M, N);
    unsigned int k = 0, s = 0;
    SetWords(T, 0, 3 * N);
    b[0] = 1;
    CopyWords(f, A, NA);
    CopyWords(g, M, N);
    while (1)
    {
        word t = f[0];
        while (!t)
        {
            if (EvenWordCount(f, fgLen) == 0)
            {
                SetWords(R, 0, N);
                return 0;
            }
            ShiftWordsRightByWords(f, fgLen, 1);
            if (c[bcLen - 1]) bcLen += 2;
            assert(bcLen <= N);
            ShiftWordsLeftByWords(c, bcLen, 1);
            k += WORD_BITS;
            t = f[0];
        }
        unsigned int i = 0;
        while (t% 2 == 0)
        {
            t >>= 1;
            i++;
        }
        k += i;
        if (t == 1 && f[1] == 0 && EvenWordCount(f, fgLen) == 2)
        {
            if (s% 2 == 0)
            CopyWords(R, b, N);
            else
            Subtract(R, M, b, N);
            return k;
        }
        ShiftWordsRightByBits(f, fgLen, i);
        t = ShiftWordsLeftByBits(c, bcLen, i);
        if (t)
        {
            c[bcLen] = t;
            bcLen += 2;
            assert(bcLen <= N);
        }
        if (f[fgLen - 2] == 0 && g[fgLen - 2] == 0 && f[fgLen - 1] == 0 && g[fgLen - 1] == 0)
        fgLen -= 2;
        if (Compare(f, g, fgLen) == - 1)
        {
            std::swap(f, g);
            std::swap(b, c);
            s++;
        }
        Subtract(f, f, g, fgLen);
        if (Add(b, b, c, bcLen))
        {
            b[bcLen] = 1;
            bcLen += 2;
            assert(bcLen <= N);
        }
    }
}

// R[N] - result = A/(2^k) mod M
// A[N] - input
// M[N] - modulus

void DivideByPower2Mod(word * R, const word * A, unsigned int k, const word * M, unsigned int N)
{
    CopyWords(R, A, N);
    while (k--)
    {
        if (R[0]% 2 == 0)
        ShiftWordsRightByBits(R, N, 1);
        else
        {
            word carry = Add(R, R, M, N);
            ShiftWordsRightByBits(R, N, 1);
            R[N - 1] += carry << (WORD_BITS - 1);
        }
    }
}

// R[N] - result = A*(2^k) mod M
// A[N] - input
// M[N] - modulus

void MultiplyByPower2Mod(word * R, const word * A, unsigned int k, const word * M, unsigned int N)
{
    CopyWords(R, A, N);
    while (k--)
    if (ShiftWordsLeftByBits(R, N, 1) || Compare(R, M, N) >= 0)
    Subtract(R, R, M, N);
}

// ******************************************************************

static const unsigned int RoundupSizeTable[] =
{
    2, 2, 2, 4, 4, 8, 8, 8, 8
};

static inline unsigned int RoundupSize(unsigned int n)
{
    if (n <= 8)
    return RoundupSizeTable[n];
    else if(n <= 16)
    return 16;
    else if(n <= 32)
    return 32;
    else if(n <= 64)
    return 64;
    else return 1U <<BitPrecision(n - 1);
}

Integer::Integer()
: reg(2), sign(POSITIVE)
{
    reg[0] = reg[1] = 0;
}

Integer::Integer(const Integer & t)
: reg(RoundupSize(t.WordCount())), sign(t.sign)
{
    CopyWords(reg, t.reg, reg.size());
}

Integer::Integer(signed long value)
: reg(2)
{
    if (value >= 0)
    sign = POSITIVE;
    else
    {
        sign = NEGATIVE;
        value = - value;
    }
    reg[0] = word(value);
    reg[1] = word(SafeRightShift < WORD_BITS, unsigned long > (value));
}

Integer::Integer(Sign s, word high, word low)
: reg(2), sign(s)
{
    reg[0] = low;
    reg[1] = high;
}

bool Integer::IsConvertableToLong() const
{
    if (ByteCount() > sizeof(long))
    return false;
    unsigned long value = reg[0];
    value += SafeLeftShift <WORD_BITS, unsigned long > (reg[1]);
    if (sign == POSITIVE)
    return(signed long) value >= 0;
    else
    return - (signed long) value <0;
}

signed long Integer::ConvertToLong() const
{
    assert(IsConvertableToLong());
    unsigned long value = reg[0];
    value += SafeLeftShift <WORD_BITS, unsigned long > (reg[1]);
    return sign == POSITIVE ? value: - (signed long) value;
}

Integer::Integer(BufferedTransformation & encodedInteger, unsigned int byteCount, Signedness s)
{
    Decode(encodedInteger, byteCount, s);
}

Integer::Integer(const byte * encodedInteger, unsigned int byteCount, Signedness s)
{
    Decode(encodedInteger, byteCount, s);
}

Integer::Integer(BufferedTransformation & bt)
{
    BERDecode(bt);
}

Integer::Integer(RandomNumberGenerator & rng, unsigned int bitcount)
{
    Randomize(rng, bitcount);
}

Integer::Integer(RandomNumberGenerator & rng, const Integer & min, const Integer & max, RandomNumberType rnType, const Integer & equiv, const Integer & mod)
{
    if (!Randomize(rng, min, max, rnType, equiv, mod))
    throw Integer::RandomNumberNotFound();
}

Integer Integer::Power2(unsigned int e)
{
    Integer r((word) 0, BitsToWords(e + 1));
    r.SetBit(e);
    return r;
}

const Integer & Integer::Zero()
{
    static const Integer zero;
    return zero;
}

const Integer & Integer::One()
{
    static const Integer one(1, 2);
    return one;
}

const Integer & Integer::Two()
{
    static const Integer two(2, 2);
    return two;
}

bool Integer::operator ! () const
{
    return IsNegative() ? false: (reg[0] == 0 && WordCount() == 0);
}

Integer & Integer::operator = (const Integer & t)
{
    if (this != & t)
    {
        reg.New(RoundupSize(t.WordCount()));
        CopyWords(reg, t.reg, reg.size());
        sign = t.sign;
    }
    return * this;
}

bool Integer::GetBit(unsigned int n) const
{
    if (n/ WORD_BITS >= reg.size())
    return 0;
    else
    return bool((reg[n/ WORD_BITS] >> (n % WORD_BITS)) & 1);
}

void Integer::SetBit(unsigned int n, bool value)
{
    if (value)
    {
        reg.CleanGrow(RoundupSize(BitsToWords(n + 1)));
        reg[n/ WORD_BITS] |= (word(1) << (n% WORD_BITS));
    }
    else
    {
        if (n/ WORD_BITS < reg.size())
        reg[n/ WORD_BITS] &= ~ (word(1) << (n% WORD_BITS));
    }
}

byte Integer::GetByte(unsigned int n) const
{
    if (n/ WORD_SIZE >= reg.size())
    return 0;
    else
    return byte(reg[n/ WORD_SIZE] >> ((n% WORD_SIZE) * 8));
}

void Integer::SetByte(unsigned int n, byte value)
{
    reg.CleanGrow(RoundupSize(BytesToWords(n + 1)));
    reg[n/ WORD_SIZE] &= ~ (word(0xff) << 8 * (n% WORD_SIZE));
    reg[n/ WORD_SIZE] |= (word(value) << 8 * (n% WORD_SIZE));
}

unsigned long Integer::GetBits(unsigned int i, unsigned int n) const
{
    assert(n <= sizeof(unsigned long) * 8);
    unsigned long v = 0;
    for (unsigned int j = 0 ; j < n ; j++)
    v |= GetBit(i + j) <<j;
    return v;
}

Integer Integer::operator - () const
{
    Integer result( * this);
    result.Negate();
    return result;
}

Integer Integer::AbsoluteValue() const
{
    Integer result( * this);
    result.sign = POSITIVE;
    return result;
}

void Integer::swap(Integer & a)
{
    reg.swap(a.reg);
    std::swap(sign, a.sign);
}

Integer::Integer(word value, unsigned int length)
: reg(RoundupSize(length)), sign(POSITIVE)
{
    reg[0] = value;
    SetWords(reg + 1, 0, reg.size() - 1);
}

template <class T >
static Integer StringToInteger(const T * str)
{
    word radix;
#if (defined(__GNUC__) && __GNUC__ <= 3)		// GCC workaround
    // std::char_traits doesn't exist in GCC 2.x
    // std::char_traits<wchar_t>::length() not defined in GCC 3.2
    unsigned int length;
    for (length = 0 ; str[length] != 0 ; length++)
    {
    }
#else
    unsigned int length = std::char_traits <T >::length(str);
#endif
    Integer v;
    if (length == 0)
    return v;
    switch (str[length - 1])
    {
    case 'h':
    case 'H':
        radix = 16;
        break;
    case 'o':
    case 'O':
        radix = 8;
        break;
    case 'b':
    case 'B':
        radix = 2;
        break;
    default:
        radix = 10;
    }
    if (length > 2 && str[0] == '0' && str[1] == 'x')
    radix = 16;
    for (unsigned i = 0 ; i < length ; i++)
    {
        word digit;
        if (str[i] >= '0' && str[i] <= '9')
        digit = str[i] - '0';
        else if(str[i] >= 'A' && str[i] <= 'F')
        digit = str[i] - 'A' + 10;
        else if(str[i] >= 'a' && str[i] <= 'f')
        digit = str[i] - 'a' + 10;
        else
        digit = radix;
        if (digit < radix)
        {
            v *= radix;
            v += digit;
        }
    }
    if (str[0] == '-')
    v.Negate();
    return v;
}

Integer::Integer(const char * str)
: reg(2), sign(POSITIVE)
{
    * this = StringToInteger(str);
}

Integer::Integer(const wchar_t * str)
: reg(2), sign(POSITIVE)
{
    * this = StringToInteger(str);
}

unsigned int Integer::WordCount() const
{
    return CountWords(reg, reg.size());
}

unsigned int Integer::ByteCount() const
{
    unsigned wordCount = WordCount();
    if (wordCount)
    return(wordCount - 1) * WORD_SIZE + BytePrecision(reg[wordCount - 1]);
    else
    return 0;
}

unsigned int Integer::BitCount() const
{
    unsigned wordCount = WordCount();
    if (wordCount)
    return(wordCount - 1) * WORD_BITS + BitPrecision(reg[wordCount - 1]);
    else
    return 0;
}

void Integer::Decode(const byte * input, unsigned int inputLen, Signedness s)
{
    StringStore store(input, inputLen);
    Decode(store, inputLen, s);
}

void Integer::Decode(BufferedTransformation & bt, unsigned int inputLen, Signedness s)
{
    assert(bt.MaxRetrievable() >= inputLen);
    byte b;
    bt.Peek(b);
    sign = ((s == SIGNED) && (b & 0x80)) ? NEGATIVE: POSITIVE;
    while (inputLen > 0 && (sign == POSITIVE ? b == 0: b == 0xff))
    {
        bt.Skip(1);
        inputLen--;
        bt.Peek(b);
    }
    reg.CleanNew(RoundupSize(BytesToWords(inputLen)));
    for (unsigned int i = inputLen ; i > 0 ; i--)
    {
        bt.Get(b);
        reg[ (i - 1) / WORD_SIZE] |= b << ((i - 1) % WORD_SIZE) * 8;
    }
    if (sign == NEGATIVE)
    {
        for (unsigned i = inputLen ; i < reg.size() * WORD_SIZE ; i++)
        reg[i/ WORD_SIZE] |= 0xff << (i% WORD_SIZE) * 8;
        TwosComplement(reg, reg.size());
    }
}

unsigned int Integer::MinEncodedSize(Signedness signedness) const
{
    unsigned int outputLen = STDMAX(1U, ByteCount());
    if (signedness == UNSIGNED)
    return outputLen;
    if (NotNegative() && (GetByte(outputLen - 1) & 0x80))
    outputLen++;
    if (IsNegative() && * this < - Power2(outputLen * 8 - 1))
    outputLen++;
    return outputLen;
}

unsigned int Integer::Encode(byte * output, unsigned int outputLen, Signedness signedness) const
{
    ArraySink sink(output, outputLen);
    return Encode(sink, outputLen, signedness);
}

unsigned int Integer::Encode(BufferedTransformation & bt, unsigned int outputLen, Signedness signedness) const
{
    if (signedness == UNSIGNED || NotNegative())
    {
        for (unsigned int i = outputLen ; i > 0 ; i--)
        bt.Put(GetByte(i - 1));
    }
    else
    {
        // take two's complement of *this
        Integer temp = Integer::Power2(8 * STDMAX(ByteCount(), outputLen)) + * this;
        for (unsigned i = 0 ; i < outputLen ; i++)
        bt.Put(temp.GetByte(outputLen - i - 1));
    }
    return outputLen;
}

void Integer::DEREncode(BufferedTransformation & bt) const
{
    DERGeneralEncoder enc(bt, INTEGER);
    Encode(enc, MinEncodedSize(SIGNED), SIGNED);
    enc.MessageEnd();
}

void Integer::BERDecode(const byte * input, unsigned int len)
{
    StringStore store(input, len);
    BERDecode(store);
}

void Integer::BERDecode(BufferedTransformation & bt)
{
    BERGeneralDecoder dec(bt, INTEGER);
    if (!dec.IsDefiniteLength() || dec.MaxRetrievable() < dec.RemainingLength())
    BERDecodeError();
    Decode(dec, dec.RemainingLength(), SIGNED);
    dec.MessageEnd();
}

void Integer::DEREncodeAsOctetString(BufferedTransformation & bt, unsigned int length) const
{
    DERGeneralEncoder enc(bt, OCTET_STRING);
    Encode(enc, length);
    enc.MessageEnd();
}

void Integer::BERDecodeAsOctetString(BufferedTransformation & bt, unsigned int length)
{
    BERGeneralDecoder dec(bt, OCTET_STRING);
    if (!dec.IsDefiniteLength() || dec.RemainingLength() != length)
    BERDecodeError();
    Decode(dec, length);
    dec.MessageEnd();
}

unsigned int Integer::OpenPGPEncode(byte * output, unsigned int len) const
{
    ArraySink sink(output, len);
    return OpenPGPEncode(sink);
}

unsigned int Integer::OpenPGPEncode(BufferedTransformation & bt) const
{
    word16 bitCount = BitCount();
    bt.PutWord16(bitCount);
    return 2 + Encode(bt, BitsToBytes(bitCount));
}

void Integer::OpenPGPDecode(const byte * input, unsigned int len)
{
    StringStore store(input, len);
    OpenPGPDecode(store);
}

void Integer::OpenPGPDecode(BufferedTransformation & bt)
{
    word16 bitCount;
    if (bt.GetWord16(bitCount) != 2 || bt.MaxRetrievable() < BitsToBytes(bitCount))
    throw OpenPGPDecodeErr();
    Decode(bt, BitsToBytes(bitCount));
}

void Integer::Randomize(RandomNumberGenerator & rng, unsigned int nbits)
{
    const unsigned int nbytes = nbits/ 8 + 1;
    SecByteBlock buf(nbytes);
    rng.GenerateBlock(buf, nbytes);
    if (nbytes)
    buf[0] = (byte) Crop(buf[0], nbits % 8);
    Decode(buf, nbytes, UNSIGNED);
}

void Integer::Randomize(RandomNumberGenerator & rng, const Integer & min, const Integer & max)
{
    if (min > max)
    throw InvalidArgument("Integer: Min must be no greater than Max");
    Integer range = max - min;
    const unsigned int nbits = range.BitCount();
    do
    {
        Randomize(rng, nbits);
    }
    while ( * this > range);
    * this += min;
}

bool Integer::Randomize(RandomNumberGenerator & rng, const Integer & min, const Integer & max, RandomNumberType rnType, const Integer & equiv, const Integer & mod)
{
    return GenerateRandomNoThrow(rng, MakeParameters("Min", min)("Max", max)("RandomNumberType", rnType)("EquivalentTo", equiv)("Mod", mod));
}

class KDF2_RNG: public RandomNumberGenerator
{
    public:
    KDF2_RNG(const byte * seed, unsigned int seedSize)
    : m_counter(0), m_counterAndSeed(seedSize + 4)
    {
        memcpy(m_counterAndSeed + 4, seed, seedSize);
    }
    byte GenerateByte()
    {
        byte b;
        GenerateBlock( & b, 1);
        return b;
    }
    void GenerateBlock(byte * output, unsigned int size)
    {
        UnalignedPutWord(BIG_ENDIAN_ORDER, m_counterAndSeed, m_counter);
        ++m_counter;
        P1363_KDF2 <SHA1 >::DeriveKey(output, size, m_counterAndSeed, m_counterAndSeed.size());
    }
    private:
    word32 m_counter;
    SecByteBlock m_counterAndSeed;
};

bool Integer::GenerateRandomNoThrow(RandomNumberGenerator & i_rng, const NameValuePairs & params)
{
    Integer min = params.GetValueWithDefault("Min", Integer::Zero());
    Integer max;
    if (!params.GetValue("Max", max))
    {
        int bitLength;
        if (params.GetIntValue("BitLength", bitLength))
        max = Integer::Power2(bitLength);
        else
        throw InvalidArgument("Integer: missing Max argument");
    }
    if (min > max)
    throw InvalidArgument("Integer: Min must be no greater than Max");
    Integer equiv = params.GetValueWithDefault("EquivalentTo", Integer::Zero());
    Integer mod = params.GetValueWithDefault("Mod", Integer::One());
    if (equiv.IsNegative() || equiv >= mod)
    throw InvalidArgument("Integer: invalid EquivalentTo and/or Mod argument");
    Integer::RandomNumberType rnType = params.GetValueWithDefault("RandomNumberType", Integer::ANY);
    member_ptr <KDF2_RNG > kdf2Rng;
    ConstByteArrayParameter seed;
    if (params.GetValue("Seed", seed))
    {
        ByteQueue bq;
        DERSequenceEncoder seq(bq);
        min.DEREncode(seq);
        max.DEREncode(seq);
        equiv.DEREncode(seq);
        mod.DEREncode(seq);
        DEREncodeUnsigned(seq, rnType);
        DEREncodeOctetString(seq, seed.begin(), seed.size());
        seq.MessageEnd();
        SecByteBlock finalSeed(bq.MaxRetrievable());
        bq.Get(finalSeed, finalSeed.size());
        kdf2Rng.reset(new KDF2_RNG(finalSeed.begin(), finalSeed.size()));
    }
    RandomNumberGenerator & rng = kdf2Rng.get() ? (RandomNumberGenerator &) * kdf2Rng: i_rng;
    switch (rnType)
    {
    case ANY:
        if (mod == One())
        Randomize(rng, min, max);
        else
        {
            Integer min1 = min + (equiv - min) % mod;
            if (max < min1)
            return false;
            Randomize(rng, Zero(), (max - min1) / mod);
            * this *= mod;
            * this += min1;
        }
        return true;
    case PRIME:
        {
            const PrimeSelector * pSelector = params.GetValueWithDefault("PointerToPrimeSelector", (const PrimeSelector *) NULL);
            int i;
            i = 0;
            while (1)
            {
                if (++i == 16)
                {
                    // check if there are any suitable primes in [min, max]
                    Integer first = min;
                    if (FirstPrime(first, max, equiv, mod, pSelector))
                    {
                        // if there is only one suitable prime, we're done
                        * this = first;
                        if (!FirstPrime(first, max, equiv, mod, pSelector))
                        return true;
                    }
                    else
                    return false;
                }
                Randomize(rng, min, max);
                if (FirstPrime( * this, STDMIN( * this + mod * PrimeSearchInterval(max), max), equiv, mod, pSelector))
                return true;
            }
        }
    default:
        throw InvalidArgument("Integer: invalid RandomNumberType argument");
    }
}

std::istream & operator >> (std::istream & in, Integer & a)
{
    char c;
    unsigned int length = 0;
    SecBlock <char > str(length + 16);
    std::ws(in);
    do
    {
        in.read( & c, 1);
        str[length++] = c;
        if (length >= str.size())
        str.Grow(length + 16);
    }
    while (in && (c == '-' || c == 'x' || (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F') || c == 'h' || c == 'H' || c == 'o' || c == 'O' || c == ',' || c == '.'));
    if (in.gcount())
    in.putback(c);
    str[length - 1] = '\0';
    a = Integer(str);
    return in;
}

std::ostream & operator << (std::ostream & out, const Integer & a)
{
    // Get relevant conversion specifications from ostream.
    long f = out.flags() & std::ios::basefield;
    // Get base digits.
    int base, block;
    char suffix;
    switch (f)
    {
    case std::ios::oct:
        base = 8;
        block = 8;
        suffix = 'o';
        break;
    case std::ios::hex:
        base = 16;
        block = 4;
        suffix = 'h';
        break;
    default:
        base = 10;
        block = 3;
        suffix = '.';
    }
    SecBlock <char > s(a.BitCount() / (BitPrecision(base) - 1) + 1);
    Integer temp1 = a, temp2;
    unsigned i = 0;
    const char vec[] ="0123456789ABCDEF";
    if (a.IsNegative())
    {
        out << '-';
        temp1.Negate();
    }
    if (!a)
    out << '0';
    while (! !temp1)
    {
        word digit;
        Integer::Divide(digit, temp2, temp1, base);
        s[i++] = vec[digit];
        temp1 = temp2;
    }
    while (i--)
    {
        out <<s[i];
        //		if (i && !(i%block))
        //			out << ",";
    }
    return out <<suffix;
}

Integer & Integer::operator++ ()
{
    if (NotNegative())
    {
        if (Increment(reg, reg.size()))
        {
            reg.CleanGrow(2 * reg.size());
            reg[reg.size() / 2] = 1;
        }
    }
    else
    {
        word borrow = Decrement(reg, reg.size());
        assert(!borrow);
        if (WordCount() == 0)
        * this = Zero();
    }
    return * this;
}

Integer & Integer::operator-- ()
{
    if (IsNegative())
    {
        if (Increment(reg, reg.size()))
        {
            reg.CleanGrow(2 * reg.size());
            reg[reg.size() / 2] = 1;
        }
    }
    else
    {
        if (Decrement(reg, reg.size()))
        * this = - One();
    }
    return * this;
}

void PositiveAdd(Integer & sum, const Integer & a, const Integer & b)
{
    word carry;
    if (a.reg.size() == b.reg.size())
    carry = Add(sum.reg, a.reg, b.reg, a.reg.size());
    else if(a.reg.size() > b.reg.size())
    {
        carry = Add(sum.reg, a.reg, b.reg, b.reg.size());
        CopyWords(sum.reg + b.reg.size(), a.reg + b.reg.size(), a.reg.size() - b.reg.size());
        carry = Increment(sum.reg + b.reg.size(), a.reg.size() - b.reg.size(), carry);
    }
    else
    {
        carry = Add(sum.reg, a.reg, b.reg, a.reg.size());
        CopyWords(sum.reg + a.reg.size(), b.reg + a.reg.size(), b.reg.size() - a.reg.size());
        carry = Increment(sum.reg + a.reg.size(), b.reg.size() - a.reg.size(), carry);
    }
    if (carry)
    {
        sum.reg.CleanGrow(2 * sum.reg.size());
        sum.reg[sum.reg.size() / 2] = 1;
    }
    sum.sign = Integer::POSITIVE;
}

void PositiveSubtract(Integer & diff, const Integer & a, const Integer & b)
{
    unsigned aSize = a.WordCount();
    aSize += aSize% 2;
    unsigned bSize = b.WordCount();
    bSize += bSize% 2;
    if (aSize == bSize)
    {
        if (Compare(a.reg, b.reg, aSize) >= 0)
        {
            Subtract(diff.reg, a.reg, b.reg, aSize);
            diff.sign = Integer::POSITIVE;
        }
        else
        {
            Subtract(diff.reg, b.reg, a.reg, aSize);
            diff.sign = Integer::NEGATIVE;
        }
    }
    else if(aSize > bSize)
    {
        word borrow = Subtract(diff.reg, a.reg, b.reg, bSize);
        CopyWords(diff.reg + bSize, a.reg + bSize, aSize - bSize);
        borrow = Decrement(diff.reg + bSize, aSize - bSize, borrow);
        assert(!borrow);
        diff.sign = Integer::POSITIVE;
    }
    else
    {
        word borrow = Subtract(diff.reg, b.reg, a.reg, aSize);
        CopyWords(diff.reg + aSize, b.reg + aSize, bSize - aSize);
        borrow = Decrement(diff.reg + aSize, bSize - aSize, borrow);
        assert(!borrow);
        diff.sign = Integer::NEGATIVE;
    }
}

Integer Integer::Plus(const Integer & b) const
{
    Integer sum((word) 0, STDMAX(reg.size(), b.reg.size()));
    if (NotNegative())
    {
        if (b.NotNegative())
        PositiveAdd(sum, * this, b);
        else
        PositiveSubtract(sum, * this, b);
    }
    else
    {
        if (b.NotNegative())
        PositiveSubtract(sum, b, * this);
        else
        {
            PositiveAdd(sum, * this, b);
            sum.sign = Integer::NEGATIVE;
        }
    }
    return sum;
}

Integer & Integer::operator += (const Integer & t)
{
    reg.CleanGrow(t.reg.size());
    if (NotNegative())
    {
        if (t.NotNegative())
        PositiveAdd( * this, * this, t);
        else
        PositiveSubtract( * this, * this, t);
    }
    else
    {
        if (t.NotNegative())
        PositiveSubtract( * this, t, * this);
        else
        {
            PositiveAdd( * this, * this, t);
            sign = Integer::NEGATIVE;
        }
    }
    return * this;
}

Integer Integer::Minus(const Integer & b) const
{
    Integer diff((word) 0, STDMAX(reg.size(), b.reg.size()));
    if (NotNegative())
    {
        if (b.NotNegative())
        PositiveSubtract(diff, * this, b);
        else
        PositiveAdd(diff, * this, b);
    }
    else
    {
        if (b.NotNegative())
        {
            PositiveAdd(diff, * this, b);
            diff.sign = Integer::NEGATIVE;
        }
        else
        PositiveSubtract(diff, b, * this);
    }
    return diff;
}

Integer & Integer::operator -= (const Integer & t)
{
    reg.CleanGrow(t.reg.size());
    if (NotNegative())
    {
        if (t.NotNegative())
        PositiveSubtract( * this, * this, t);
        else
        PositiveAdd( * this, * this, t);
    }
    else
    {
        if (t.NotNegative())
        {
            PositiveAdd( * this, * this, t);
            sign = Integer::NEGATIVE;
        }
        else
        PositiveSubtract( * this, t, * this);
    }
    return * this;
}

Integer & Integer::operator <<= (unsigned int n)
{
    const unsigned int wordCount = WordCount();
    const unsigned int shiftWords = n / WORD_BITS;
    const unsigned int shiftBits = n % WORD_BITS;
    reg.CleanGrow(RoundupSize(wordCount + BitsToWords(n)));
    ShiftWordsLeftByWords(reg, wordCount + shiftWords, shiftWords);
    ShiftWordsLeftByBits(reg + shiftWords, wordCount + BitsToWords(shiftBits), shiftBits);
    return * this;
}

Integer & Integer::operator >>= (unsigned int n)
{
    const unsigned int wordCount = WordCount();
    const unsigned int shiftWords = n / WORD_BITS;
    const unsigned int shiftBits = n % WORD_BITS;
    ShiftWordsRightByWords(reg, wordCount, shiftWords);
    if (wordCount > shiftWords)
    ShiftWordsRightByBits(reg, wordCount - shiftWords, shiftBits);
    // avoid -0:
    if (IsNegative() && WordCount() == 0)
    * this = Zero();
    return * this;
}

void PositiveMultiply(Integer & product, const Integer & a, const Integer & b)
{
    unsigned aSize = RoundupSize(a.WordCount());
    unsigned bSize = RoundupSize(b.WordCount());
    product.reg.CleanNew(RoundupSize(aSize + bSize));
    product.sign = Integer::POSITIVE;
    SecAlignedWordBlock workspace(aSize + bSize);
    AsymmetricMultiply(product.reg, workspace, a.reg, aSize, b.reg, bSize);
}

void Multiply(Integer & product, const Integer & a, const Integer & b)
{
    PositiveMultiply(product, a, b);
    if (a.NotNegative() != b.NotNegative())
    product.Negate();
}

Integer Integer::Times(const Integer & b) const
{
    Integer product;
    Multiply(product, * this, b);
    return product;
}

 /*
 void PositiveDivide(Integer &remainder, Integer &quotient,
 const Integer &dividend, const Integer &divisor)
 {
 remainder.reg.CleanNew(divisor.reg.size());
 remainder.sign = Integer::POSITIVE;
 quotient.reg.New(0);
 quotient.sign = Integer::POSITIVE;
 unsigned i=dividend.BitCount();
 while (i--)
 {
 word overflow = ShiftWordsLeftByBits(remainder.reg, remainder.reg.size(), 1);
 remainder.reg[0] |= dividend[i];
 if (overflow || remainder >= divisor)
 {
 Subtract(remainder.reg, remainder.reg, divisor.reg, remainder.reg.size());
 quotient.SetBit(i);
 }
 }
 }
    */

void PositiveDivide(Integer & remainder, Integer & quotient,
const Integer & a, const Integer & b)
{
    unsigned aSize = a.WordCount();
    unsigned bSize = b.WordCount();
    if (!bSize)
    throw Integer::DivideByZero();
    if (a.PositiveCompare(b) == - 1)
    {
        remainder = a;
        remainder.sign = Integer::POSITIVE;
        quotient = Integer::Zero();
        return;
    }
    aSize += aSize% 2;
    // round up to next even number
    bSize += bSize% 2;
    remainder.reg.CleanNew(RoundupSize(bSize));
    remainder.sign = Integer::POSITIVE;
    quotient.reg.CleanNew(RoundupSize(aSize - bSize + 2));
    quotient.sign = Integer::POSITIVE;
    SecAlignedWordBlock T(aSize + 2 * bSize + 4);
    Divide(remainder.reg, quotient.reg, T, a.reg, aSize, b.reg, bSize);
}

void Integer::Divide(Integer & remainder, Integer & quotient, const Integer & dividend, const Integer & divisor)
{
    PositiveDivide(remainder, quotient, dividend, divisor);
    if (dividend.IsNegative())
    {
        quotient.Negate();
        if (remainder.NotZero())
        {
            --quotient;
            remainder = divisor.AbsoluteValue() - remainder;
        }
    }
    if (divisor.IsNegative())
    quotient.Negate();
}

void Integer::DivideByPowerOf2(Integer & r, Integer & q, const Integer & a, unsigned int n)
{
    q = a;
    q >>= n;
    const unsigned int wordCount = BitsToWords(n);
    if (wordCount <= a.WordCount())
    {
        r.reg.resize(RoundupSize(wordCount));
        CopyWords(r.reg, a.reg, wordCount);
        SetWords(r.reg + wordCount, 0, r.reg.size() - wordCount);
        if (n % WORD_BITS != 0)
        r.reg[wordCount - 1] %= (1 << (n % WORD_BITS));
    }
    else
    {
        r.reg.resize(RoundupSize(a.WordCount()));
        CopyWords(r.reg, a.reg, r.reg.size());
    }
    r.sign = POSITIVE;
    if (a.IsNegative() && r.NotZero())
    {
        --q;
        r = Power2(n) - r;
    }
}

Integer Integer::DividedBy(const Integer & b) const
{
    Integer remainder, quotient;
    Integer::Divide(remainder, quotient, * this, b);
    return quotient;
}

Integer Integer::Modulo(const Integer & b) const
{
    Integer remainder, quotient;
    Integer::Divide(remainder, quotient, * this, b);
    return remainder;
}

void Integer::Divide(word & remainder, Integer & quotient, const Integer & dividend, word divisor)
{
    if (!divisor)
    throw Integer::DivideByZero();
    assert(divisor);
    // divisor is a power of 2:
    if ((divisor & (divisor - 1)) == 0)
    {
        quotient = dividend >> (BitPrecision(divisor) - 1);
        remainder = dividend.reg[0] & (divisor - 1);
        return;
    }
    unsigned int i = dividend.WordCount();
    quotient.reg.CleanNew(RoundupSize(i));
    remainder = 0;
    while (i--)
    {
        quotient.reg[i] = word(MAKE_DWORD(dividend.reg[i], remainder) / divisor);
        remainder = word(MAKE_DWORD(dividend.reg[i], remainder) % divisor);
    }
    if (dividend.NotNegative())
    quotient.sign = POSITIVE;
    else
    {
        quotient.sign = NEGATIVE;
        if (remainder)
        {
            --quotient;
            remainder = divisor - remainder;
        }
    }
}

Integer Integer::DividedBy(word b) const
{
    word remainder;
    Integer quotient;
    Integer::Divide(remainder, quotient, * this, b);
    return quotient;
}

word Integer::Modulo(word divisor) const
{
    if (!divisor)
    throw Integer::DivideByZero();
    assert(divisor);
    word remainder;
    // divisor is a power of 2:
    if ((divisor & (divisor - 1)) == 0)
    remainder = reg[0] & (divisor - 1);
    else
    {
        unsigned int i = WordCount();
        if (divisor <= 5)
        {
            dword sum = 0;
            while (i--)
            sum += reg[i];
            remainder = word(sum% divisor);
        }
        else
        {
            remainder = 0;
            while (i--)
            remainder = word(MAKE_DWORD(reg[i], remainder) % divisor);
        }
    }
    if (IsNegative() && remainder)
    remainder = divisor - remainder;
    return remainder;
}

void Integer::Negate()
{
    // don't flip sign if *this==0:
    if (! ! ( * this))
    sign = Sign(1 - sign);
}

int Integer::PositiveCompare(const Integer & t) const
{
    unsigned size = WordCount(), tSize = t.WordCount();
    if (size == tSize)
    return CryptoXMpp::Compare(reg, t.reg, size);
    else
    return size > tSize ? 1: - 1;
}

int Integer::Compare(const Integer & t) const
{
    if (NotNegative())
    {
        if (t.NotNegative())
        return PositiveCompare(t);
        else
        return 1;
    }
    else
    {
        if (t.NotNegative())
        return - 1;
        else
        return - PositiveCompare(t);
    }
}

Integer Integer::SquareRoot() const
{
    if (!IsPositive())
    return Zero();
    // overestimate square root
    Integer x, y = Power2((BitCount() + 1) / 2);
    assert(y * y >= * this);
    do
    {
        x = y;
        y = (x + * this/ x) >> 1;
    }
    while (y < x);
    return x;
}

bool Integer::IsSquare() const
{
    Integer r = SquareRoot();
    return * this == r.Squared();
}

bool Integer::IsUnit() const
{
    return(WordCount() == 1) && (reg[0] == 1);
}

Integer Integer::MultiplicativeInverse() const
{
    return IsUnit() ? * this: Zero();
}

Integer a_times_b_mod_c(const Integer & x, const Integer & y, const Integer & m)
{
    return x * y% m;
}

Integer a_exp_b_mod_c(const Integer & x, const Integer & e, const Integer & m)
{
    ModularArithmetic mr(m);
    return mr.Exponentiate(x, e);
}

Integer Integer::Gcd(const Integer & a, const Integer & b)
{
    return EuclideanDomainOf <Integer > () .Gcd(a, b);
}

Integer Integer::InverseMod(const Integer & m) const
{
    assert(m.NotNegative());
    if (IsNegative() || * this >= m)
    return( * this% m) .InverseMod(m);
    if (m.IsEven())
    {
        if (!m || IsEven())
        return Zero();
        // no inverse
        if ( * this == One())
        return One();
        Integer u = m.InverseMod( * this);
        return !u ? Zero(): (m * ( * this - u) + 1) / ( * this);
    }
    SecBlock <word > T(m.reg.size() * 4);
    Integer r((word) 0, m.reg.size());
    unsigned k = AlmostInverse(r.reg, T, reg, reg.size(), m.reg, m.reg.size());
    DivideByPower2Mod(r.reg, r.reg, k, m.reg, m.reg.size());
    return r;
}

word Integer::InverseMod(const word mod) const
{
    word g0 = mod, g1 = * this % mod;
    word v0 = 0, v1 = 1;
    word y;
    while (g1)
    {
        if (g1 == 1)
        return v1;
        y = g0 / g1;
        g0 = g0 % g1;
        v0 += y * v1;
        if (!g0)
        break;
        if (g0 == 1)
        return mod - v0;
        y = g1 / g0;
        g1 = g1 % g0;
        v1 += y * v0;
    }
    return 0;
}

// ********************************************************

ModularArithmetic::ModularArithmetic(BufferedTransformation & bt)
{
    BERSequenceDecoder seq(bt);
    OID oid(seq);
    if (oid != ASN1::prime_field())
    BERDecodeError();
    modulus.BERDecode(seq);
    seq.MessageEnd();
    result.reg.resize(modulus.reg.size());
}

void ModularArithmetic::DEREncode(BufferedTransformation & bt) const
{
    DERSequenceEncoder seq(bt);
    ASN1::prime_field() .DEREncode(seq);
    modulus.DEREncode(seq);
    seq.MessageEnd();
}

void ModularArithmetic::DEREncodeElement(BufferedTransformation & out, const Element & a) const
{
    a.DEREncodeAsOctetString(out, MaxElementByteLength());
}

void ModularArithmetic::BERDecodeElement(BufferedTransformation & in, Element & a) const
{
    a.BERDecodeAsOctetString(in, MaxElementByteLength());
}

const Integer & ModularArithmetic::Half(const Integer & a) const
{
    if (a.reg.size() == modulus.reg.size())
    {
        CryptoXMpp::DivideByPower2Mod(result.reg.begin(), a.reg, 1, modulus.reg, a.reg.size());
        return result;
    }
    else
    return result1 = (a.IsEven() ? (a >> 1): ((a + modulus) >> 1));
}

const Integer & ModularArithmetic::Add(const Integer & a, const Integer & b) const
{
    if (a.reg.size() == modulus.reg.size() && b.reg.size() == modulus.reg.size())
    {
        if (CryptoXMpp::Add(result.reg.begin(), a.reg, b.reg, a.reg.size())
        || Compare(result.reg, modulus.reg, a.reg.size()) >= 0)
        {
            CryptoXMpp::Subtract(result.reg.begin(), result.reg, modulus.reg, a.reg.size());
        }
        return result;
    }
    else
    {
        result1 = a + b;
        if (result1 >= modulus)
        result1 -= modulus;
        return result1;
    }
}

Integer & ModularArithmetic::Accumulate(Integer & a, const Integer & b) const
{
    if (a.reg.size() == modulus.reg.size() && b.reg.size() == modulus.reg.size())
    {
        if (CryptoXMpp::Add(a.reg, a.reg, b.reg, a.reg.size())
        || Compare(a.reg, modulus.reg, a.reg.size()) >= 0)
        {
            CryptoXMpp::Subtract(a.reg, a.reg, modulus.reg, a.reg.size());
        }
    }
    else
    {
        a += b;
        if (a >= modulus)
        a -= modulus;
    }
    return a;
}

const Integer & ModularArithmetic::Subtract(const Integer & a, const Integer & b) const
{
    if (a.reg.size() == modulus.reg.size() && b.reg.size() == modulus.reg.size())
    {
        if (CryptoXMpp::Subtract(result.reg.begin(), a.reg, b.reg, a.reg.size()))
        CryptoXMpp::Add(result.reg.begin(), result.reg, modulus.reg, a.reg.size());
        return result;
    }
    else
    {
        result1 = a - b;
        if (result1.IsNegative())
        result1 += modulus;
        return result1;
    }
}

Integer & ModularArithmetic::Reduce(Integer & a, const Integer & b) const
{
    if (a.reg.size() == modulus.reg.size() && b.reg.size() == modulus.reg.size())
    {
        if (CryptoXMpp::Subtract(a.reg, a.reg, b.reg, a.reg.size()))
        CryptoXMpp::Add(a.reg, a.reg, modulus.reg, a.reg.size());
    }
    else
    {
        a -= b;
        if (a.IsNegative())
        a += modulus;
    }
    return a;
}

const Integer & ModularArithmetic::Inverse(const Integer & a) const
{
    if (!a)
    return a;
    CopyWords(result.reg.begin(), modulus.reg, modulus.reg.size());
    if (CryptoXMpp::Subtract(result.reg.begin(), result.reg, a.reg, a.reg.size()))
    Decrement(result.reg.begin() + a.reg.size(), 1, modulus.reg.size() - a.reg.size());
    return result;
}

Integer ModularArithmetic::CascadeExponentiate(const Integer & x, const Integer & e1, const Integer & y, const Integer & e2) const
{
    if (modulus.IsOdd())
    {
        MontgomeryRepresentation dr(modulus);
        return dr.ConvertOut(dr.CascadeExponentiate(dr.ConvertIn(x), e1, dr.ConvertIn(y), e2));
    }
    else
    return AbstractRing <Integer >::CascadeExponentiate(x, e1, y, e2);
}

void ModularArithmetic::SimultaneousExponentiate(Integer * results, const Integer & base, const Integer * exponents, unsigned int exponentsCount) const
{
    if (modulus.IsOdd())
    {
        MontgomeryRepresentation dr(modulus);
        dr.SimultaneousExponentiate(results, dr.ConvertIn(base), exponents, exponentsCount);
        for (unsigned int i = 0 ; i < exponentsCount ; i++)
        results[i] = dr.ConvertOut(results[i]);
    }
    else
    AbstractRing <Integer >::SimultaneousExponentiate(results, base, exponents, exponentsCount);
}

// modulus must be odd:
MontgomeryRepresentation::MontgomeryRepresentation(const Integer & m)
: ModularArithmetic(m),
u((word) 0, modulus.reg.size()),
workspace(5 * modulus.reg.size())
{
    if (!modulus.IsOdd())
    throw InvalidArgument("MontgomeryRepresentation: Montgomery representation requires an odd modulus");
    RecursiveInverseModPower2(u.reg, workspace, modulus.reg, modulus.reg.size());
}

const Integer & MontgomeryRepresentation::Multiply(const Integer & a, const Integer & b) const
{
    word * const T = workspace.begin();
    word * const R = result.reg.begin();
    const unsigned int N = modulus.reg.size();
    assert(a.reg.size() <= N && b.reg.size() <= N);
    AsymmetricMultiply(T, T + 2 * N, a.reg, a.reg.size(), b.reg, b.reg.size());
    SetWords(T + a.reg.size() + b.reg.size(), 0, 2 * N - a.reg.size() - b.reg.size());
    MontgomeryReduce(R, T + 2 * N, T, modulus.reg, u.reg, N);
    return result;
}

const Integer & MontgomeryRepresentation::Square(const Integer & a) const
{
    word * const T = workspace.begin();
    word * const R = result.reg.begin();
    const unsigned int N = modulus.reg.size();
    assert(a.reg.size() <= N);
    CryptoXMpp::Square(T, T + 2 * N, a.reg, a.reg.size());
    SetWords(T + 2 * a.reg.size(), 0, 2 * N - 2 * a.reg.size());
    MontgomeryReduce(R, T + 2 * N, T, modulus.reg, u.reg, N);
    return result;
}

Integer MontgomeryRepresentation::ConvertOut(const Integer & a) const
{
    word * const T = workspace.begin();
    word * const R = result.reg.begin();
    const unsigned int N = modulus.reg.size();
    assert(a.reg.size() <= N);
    CopyWords(T, a.reg, a.reg.size());
    SetWords(T + a.reg.size(), 0, 2 * N - a.reg.size());
    MontgomeryReduce(R, T + 2 * N, T, modulus.reg, u.reg, N);
    return result;
}

const Integer & MontgomeryRepresentation::MultiplicativeInverse(const Integer & a) const
{
    //	  return (EuclideanMultiplicativeInverse(a, modulus)<<(2*WORD_BITS*modulus.reg.size()))%modulus;
    word * const T = workspace.begin();
    word * const R = result.reg.begin();
    const unsigned int N = modulus.reg.size();
    assert(a.reg.size() <= N);
    CopyWords(T, a.reg, a.reg.size());
    SetWords(T + a.reg.size(), 0, 2 * N - a.reg.size());
    MontgomeryReduce(R, T + 2 * N, T, modulus.reg, u.reg, N);
    unsigned k = AlmostInverse(R, T, R, N, modulus.reg, N);
    //	cout << "k=" << k << " N*32=" << 32*N << endl;
    if (k > N * WORD_BITS)
    DivideByPower2Mod(R, R, k - N * WORD_BITS, modulus.reg, N);
    else
    MultiplyByPower2Mod(R, R, N * WORD_BITS - k, modulus.reg, N);
    return result;
}

template class AbstractRing <Integer >;

// iterhash.cpp - written and placed in the public domain by Wei Dai

 /*faz:start
 template<> void ByteReverse(word16 *, const word16 *, unsigned int);
 template<> void ByteReverse(word32 *, const word32 *, unsigned int);
 #ifdef WORD64_AVAILABLE
 template<> void ByteReverse(word64 *, const word64 *, unsigned int);
 #endif
    faz:end*/

template <class T, class BASE >
IteratedHashBase <T, BASE >::IteratedHashBase(unsigned int blockSize, unsigned int digestSize)
: m_data(blockSize/ sizeof(T)), m_digest(digestSize/ sizeof(T))
, m_countHi(0), m_countLo(0)
{
}

template <class T, class BASE > void IteratedHashBase <T, BASE >::Update(const byte * input, unsigned int len)
{
    HashWordType tmp = m_countLo;
    if ((m_countLo = tmp + len) < tmp)
    m_countHi++;
    // carry from low to high
    m_countHi += SafeRightShift <8 * sizeof(HashWordType) > (len);
    unsigned int blockSize = BlockSize();
    unsigned int num = ModPowerOf2(tmp, blockSize);
    // process left over data:
    if (num != 0)
    {
        if ((num + len) >= blockSize)
        {
            memcpy((byte *) m_data.begin() + num, input, blockSize - num);
            HashBlock(m_data);
            input += (blockSize - num);
            len -= (blockSize - num);
            num = 0;
            // drop through and do the rest
        }
        else
        {
            memcpy((byte *) m_data.begin() + num, input, len);
            return;
        }
    }
    // now process the input data in blocks of blockSize bytes and save the leftovers to m_data
    if (len >= blockSize)
    {
        if (input == (byte *) m_data.begin())
        {
            assert(len == blockSize);
            HashBlock(m_data);
            return;
        }
        else if(IsAligned < T > (input))
        {
            unsigned int leftOver = HashMultipleBlocks((T *) input, len);
            input += (len - leftOver);
            len = leftOver;
        }
        else
        {
            do
            {
                // copy input first if it's not aligned correctly
                memcpy(m_data, input, blockSize);
                HashBlock(m_data);
                input += blockSize;
                len -= blockSize;
            }
            while (len >= blockSize);
        }
    }
    memcpy(m_data, input, len);
}

template <class T, class BASE > byte * IteratedHashBase <T, BASE >::CreateUpdateSpace(unsigned int & size)
{
    unsigned int blockSize = BlockSize();
    unsigned int num = ModPowerOf2(m_countLo, blockSize);
    size = blockSize - num;
    return(byte *) m_data.begin() + num;
}

template <class T, class BASE > unsigned int IteratedHashBase <T, BASE >::HashMultipleBlocks(const T * input, unsigned int length)
{
    unsigned int blockSize = BlockSize();
    do
    {
        HashBlock(input);
        input += blockSize/ sizeof(T);
        length -= blockSize;
    }
    while (length >= blockSize);
    return length;
}

template <class T, class BASE > void IteratedHashBase <T, BASE >::PadLastBlock(unsigned int lastBlockSize, byte padFirst)
{
    unsigned int blockSize = BlockSize();
    unsigned int num = ModPowerOf2(m_countLo, blockSize);
    ((byte *) m_data.begin()) [num++] = padFirst;
    if (num <= lastBlockSize)
    memset((byte *) m_data.begin() + num, 0, lastBlockSize - num);
    else
    {
        memset((byte *) m_data.begin() + num, 0, blockSize - num);
        HashBlock(m_data);
        memset(m_data, 0, lastBlockSize);
    }
}

template <class T, class BASE > void IteratedHashBase <T, BASE >::Restart()
{
    m_countLo = m_countHi = 0;
    Init();
}

#ifdef WORD64_AVAILABLE
template class IteratedHashBase <word64, HashTransformation >;
template class IteratedHashBase <word64, MessageAuthenticationCode >;
#endif

template class IteratedHashBase <word32, HashTransformation >;
template class IteratedHashBase <word32, MessageAuthenticationCode >;

// misc.cpp - written and placed in the public domain by Wei Dai

byte OAEP_P_DEFAULT[1];

void xorbuf(byte * buf, const byte * mask, unsigned int count)
{
    if (((unsigned long) buf | (unsigned long) mask | count) % WORD_SIZE == 0)
    XorWords((word *) buf, (const word *) mask, count/ WORD_SIZE);
    else
    {
        for (unsigned int i = 0 ; i < count ; i++)
        buf[i] ^= mask[i];
    }
}

void xorbuf(byte * output, const byte * input, const byte * mask, unsigned int count)
{
    if (((unsigned long) output | (unsigned long) input | (unsigned long) mask | count) % WORD_SIZE == 0)
    XorWords((word *) output, (const word *) input, (const word *) mask, count/ WORD_SIZE);
    else
    {
        for (unsigned int i = 0 ; i < count ; i++)
        output[i] = input[i] ^ mask[i];
    }
}

unsigned int Parity(unsigned long value)
{
    for (unsigned int i = 8 * sizeof(value) / 2 ; i > 0 ; i/= 2)
    value ^= value >> i;
    return(unsigned int) value & 1;
}

unsigned int BytePrecision(unsigned long value)
{
    unsigned int i;
    for (i = sizeof(value) ; i ;--i)
    if (value >> (i - 1) * 8)
    break;
    return i;
}

unsigned int BitPrecision(unsigned long value)
{
    if (!value)
    return 0;
    unsigned int l = 0, h = 8 * sizeof(value);
    while (h - l > 1)
    {
        unsigned int t = (l + h) / 2;
        if (value >> t)
        l = t;
        else
        h = t;
    }
    return h;
}

unsigned long Crop(unsigned long value, unsigned int size)
{
    if (size < 8 * sizeof(value))
    return(value & ((1L << size) - 1));
    else
    return value;
}

// mqueue.cpp - written and placed in the public domain by Wei Dai

MessageQueue::MessageQueue(unsigned int nodeSize)
: m_queue(nodeSize), m_lengths(1, 0U), m_messageCounts(1, 0U)
{
}

unsigned int MessageQueue::CopyRangeTo2(BufferedTransformation & target, unsigned long & begin, unsigned long end, const std::string & channel, bool blocking) const
{
    if (begin >= MaxRetrievable())
    return 0;
    return m_queue.CopyRangeTo2(target, begin, STDMIN(MaxRetrievable(), end), channel, blocking);
}

unsigned int MessageQueue::TransferTo2(BufferedTransformation & target, unsigned long & transferBytes, const std::string & channel, bool blocking)
{
    transferBytes = STDMIN(MaxRetrievable(), transferBytes);
    unsigned int blockedBytes = m_queue.TransferTo2(target, transferBytes, channel, blocking);
    m_lengths.front() -= transferBytes;
    return blockedBytes;
}

bool MessageQueue::GetNextMessage()
{
    if (NumberOfMessages() > 0 && !AnyRetrievable())
    {
        m_lengths.pop_front();
        if (m_messageCounts[0] == 0 && m_messageCounts.size() > 1)
        m_messageCounts.pop_front();
        return true;
    }
    else
    return false;
}

unsigned int MessageQueue::CopyMessagesTo(BufferedTransformation & target, unsigned int count, const std::string & channel) const
{
    ByteQueue::Walker walker(m_queue);
    std::deque <unsigned long >::const_iterator it = m_lengths.begin();
    unsigned int i;
    for (i = 0 ; i < count && it !=--m_lengths.end() ;++i,++it)
    {
        walker.TransferTo(target, * it, channel);
        if (GetAutoSignalPropagation())
        target.ChannelMessageEnd(channel, GetAutoSignalPropagation() - 1);
    }
    return i;
}

void MessageQueue::swap(MessageQueue & rhs)
{
    m_queue.swap(rhs.m_queue);
    m_lengths.swap(rhs.m_lengths);
}

const byte * MessageQueue::Spy(unsigned int & contiguousSize) const
{
    const byte * result = m_queue.Spy(contiguousSize);
    contiguousSize = (unsigned int) STDMIN((unsigned long) contiguousSize, MaxRetrievable());
    return result;
}

// *************************************************************

unsigned int EqualityComparisonFilter::MapChannel(const std::string & channel) const
{
    if (channel == m_firstChannel)
    return 0;
    else if(channel == m_secondChannel)
    return 1;
    else
    return 2;
}

unsigned int EqualityComparisonFilter::ChannelPut2(const std::string & channel, const byte * inString, unsigned int length, int messageEnd, bool blocking)
{
    if (!blocking)
    throw BlockingInputOnly("EqualityComparisonFilter");
    unsigned int i = MapChannel(channel);
    if (i == 2)
    return Output(3, inString, length, messageEnd, blocking, channel);
    else if(m_mismatchDetected)
    return 0;
    else
    {
        MessageQueue & q1 = m_q[i], & q2 = m_q[1 - i];
        if (q2.AnyMessages() && q2.MaxRetrievable() < length)
        goto mismatch;
        while (length > 0 && q2.AnyRetrievable())
        {
            unsigned int len = length;
            const byte * data = q2.Spy(len);
            len = STDMIN(len, length);
            if (memcmp(inString, data, len) != 0)
            goto mismatch;
            inString += len;
            length -= len;
            q2.Skip(len);
        }
        q1.Put(inString, length);
        if (messageEnd)
        {
            if (q2.AnyRetrievable())
            goto mismatch;
            else if(q2.AnyMessages())
            q2.GetNextMessage();
            else if(q2.NumberOfMessageSeries() > 0)
            goto mismatch;
            else
            q1.MessageEnd();
        }
        return 0;
        mismatch:
        return HandleMismatchDetected(blocking);
    }
}

void EqualityComparisonFilter::ChannelInitialize(const std::string & channel, const NameValuePairs & parameters, int propagation)
{
    unsigned int i = MapChannel(channel);
    if (i == 2)
    PropagateInitialize(parameters, propagation, channel);
    else
    {
        m_q[i].Initialize();
        m_mismatchDetected = false;
    }
}

bool EqualityComparisonFilter::ChannelMessageSeriesEnd(const std::string & channel, int propagation, bool blocking)
{
    unsigned int i = MapChannel(channel);
    if (i == 2)
    {
        OutputMessageSeriesEnd(4, propagation, blocking, channel);
        return false;
    }
    else if(m_mismatchDetected)
    return false;
    else
    {
        MessageQueue & q1 = m_q[i], & q2 = m_q[1 - i];
        if (q2.AnyRetrievable() || q2.AnyMessages())
        goto mismatch;
        else if(q2.NumberOfMessageSeries() > 0)
        return Output(2, (const byte *) "\1", 1, 0, blocking) != 0;
        else
        q1.MessageSeriesEnd();
        return false;
        mismatch:
        return HandleMismatchDetected(blocking);
    }
}

bool EqualityComparisonFilter::HandleMismatchDetected(bool blocking)
{
    m_mismatchDetected = true;
    if (m_throwIfNotEqual)
    throw MismatchDetected();
    return Output(1, (const byte *) "\0", 1, 0, blocking) != 0;
}

// nbtheory.cpp - written and placed in the public domain by Wei Dai

// last prime 32719:
const unsigned int maxPrimeTableSize = 3511;
const word lastSmallPrime = 32719;
unsigned int primeTableSize = 552;

word primeTable[maxPrimeTableSize] =
{
    2, 3, 5, 7, 11, 13, 17, 19,
    23, 29, 31, 37, 41, 43, 47, 53,
    59, 61, 67, 71, 73, 79, 83, 89,
    97, 101, 103, 107, 109, 113, 127, 131,
    137, 139, 149, 151, 157, 163, 167, 173,
    179, 181, 191, 193, 197, 199, 211, 223,
    227, 229, 233, 239, 241, 251, 257, 263,
    269, 271, 277, 281, 283, 293, 307, 311,
    313, 317, 331, 337, 347, 349, 353, 359,
    367, 373, 379, 383, 389, 397, 401, 409,
    419, 421, 431, 433, 439, 443, 449, 457,
    461, 463, 467, 479, 487, 491, 499, 503,
    509, 521, 523, 541, 547, 557, 563, 569,
    571, 577, 587, 593, 599, 601, 607, 613,
    617, 619, 631, 641, 643, 647, 653, 659,
    661, 673, 677, 683, 691, 701, 709, 719,
    727, 733, 739, 743, 751, 757, 761, 769,
    773, 787, 797, 809, 811, 821, 823, 827,
    829, 839, 853, 857, 859, 863, 877, 881,
    883, 887, 907, 911, 919, 929, 937, 941,
    947, 953, 967, 971, 977, 983, 991, 997,
    1009, 1013, 1019, 1021, 1031, 1033, 1039, 1049,
    1051, 1061, 1063, 1069, 1087, 1091, 1093, 1097,
    1103, 1109, 1117, 1123, 1129, 1151, 1153, 1163,
    1171, 1181, 1187, 1193, 1201, 1213, 1217, 1223,
    1229, 1231, 1237, 1249, 1259, 1277, 1279, 1283,
    1289, 1291, 1297, 1301, 1303, 1307, 1319, 1321,
    1327, 1361, 1367, 1373, 1381, 1399, 1409, 1423,
    1427, 1429, 1433, 1439, 1447, 1451, 1453, 1459,
    1471, 1481, 1483, 1487, 1489, 1493, 1499, 1511,
    1523, 1531, 1543, 1549, 1553, 1559, 1567, 1571,
    1579, 1583, 1597, 1601, 1607, 1609, 1613, 1619,
    1621, 1627, 1637, 1657, 1663, 1667, 1669, 1693,
    1697, 1699, 1709, 1721, 1723, 1733, 1741, 1747,
    1753, 1759, 1777, 1783, 1787, 1789, 1801, 1811,
    1823, 1831, 1847, 1861, 1867, 1871, 1873, 1877,
    1879, 1889, 1901, 1907, 1913, 1931, 1933, 1949,
    1951, 1973, 1979, 1987, 1993, 1997, 1999, 2003,
    2011, 2017, 2027, 2029, 2039, 2053, 2063, 2069,
    2081, 2083, 2087, 2089, 2099, 2111, 2113, 2129,
    2131, 2137, 2141, 2143, 2153, 2161, 2179, 2203,
    2207, 2213, 2221, 2237, 2239, 2243, 2251, 2267,
    2269, 2273, 2281, 2287, 2293, 2297, 2309, 2311,
    2333, 2339, 2341, 2347, 2351, 2357, 2371, 2377,
    2381, 2383, 2389, 2393, 2399, 2411, 2417, 2423,
    2437, 2441, 2447, 2459, 2467, 2473, 2477, 2503,
    2521, 2531, 2539, 2543, 2549, 2551, 2557, 2579,
    2591, 2593, 2609, 2617, 2621, 2633, 2647, 2657,
    2659, 2663, 2671, 2677, 2683, 2687, 2689, 2693,
    2699, 2707, 2711, 2713, 2719, 2729, 2731, 2741,
    2749, 2753, 2767, 2777, 2789, 2791, 2797, 2801,
    2803, 2819, 2833, 2837, 2843, 2851, 2857, 2861,
    2879, 2887, 2897, 2903, 2909, 2917, 2927, 2939,
    2953, 2957, 2963, 2969, 2971, 2999, 3001, 3011,
    3019, 3023, 3037, 3041, 3049, 3061, 3067, 3079,
    3083, 3089, 3109, 3119, 3121, 3137, 3163, 3167,
    3169, 3181, 3187, 3191, 3203, 3209, 3217, 3221,
    3229, 3251, 3253, 3257, 3259, 3271, 3299, 3301,
    3307, 3313, 3319, 3323, 3329, 3331, 3343, 3347,
    3359, 3361, 3371, 3373, 3389, 3391, 3407, 3413,
    3433, 3449, 3457, 3461, 3463, 3467, 3469, 3491,
    3499, 3511, 3517, 3527, 3529, 3533, 3539, 3541,
    3547, 3557, 3559, 3571, 3581, 3583, 3593, 3607,
    3613, 3617, 3623, 3631, 3637, 3643, 3659, 3671,
    3673, 3677, 3691, 3697, 3701, 3709, 3719, 3727,
    3733, 3739, 3761, 3767, 3769, 3779, 3793, 3797,
    3803, 3821, 3823, 3833, 3847, 3851, 3853, 3863,
    3877, 3881, 3889, 3907, 3911, 3917, 3919, 3923,
    3929, 3931, 3943, 3947, 3967, 3989, 4001, 4003
};

void BuildPrimeTable()
{
    unsigned int p = primeTable[primeTableSize - 1];
    for (unsigned int i = primeTableSize ; i < maxPrimeTableSize ; i++)
    {
        int j;
        do
        {
            p += 2;
            for (j = 1 ; j < 54 ; j++)
            if (p% primeTable[j] == 0)
            break;
        }
        while (j != 54);
        primeTable[i] = p;
    }
    primeTableSize = maxPrimeTableSize;
    assert(primeTable[primeTableSize - 1] == lastSmallPrime);
}

bool IsSmallPrime(const Integer & p)
{
    BuildPrimeTable();
    if (p.IsPositive() && p <= primeTable[primeTableSize - 1])
    return std::binary_search(primeTable, primeTable + primeTableSize, (word) p.ConvertToLong());
    else
    return false;
}

bool TrialDivision(const Integer & p, unsigned bound)
{
    assert(primeTable[primeTableSize - 1] >= bound);
    unsigned int i;
    for (i = 0 ; primeTable[i] < bound ; i++)
    if ((p % primeTable[i]) == 0)
    return true;
    if (bound == primeTable[i])
    return(p % bound == 0);
    else
    return false;
}

bool SmallDivisorsTest(const Integer & p)
{
    BuildPrimeTable();
    return !TrialDivision(p, primeTable[primeTableSize - 1]);
}

bool IsFermatProbablePrime(const Integer & n, const Integer & b)
{
    if (n <= 3)
    return n == 2 || n == 3;
    assert(n > 3 && b > 1 && b < n - 1);
    return a_exp_b_mod_c(b, n - 1, n) == 1;
}

bool IsStrongProbablePrime(const Integer & n, const Integer & b)
{
    if (n <= 3)
    return n == 2 || n == 3;
    assert(n > 3 && b > 1 && b < n - 1);
    if ((n.IsEven() && n != 2) || GCD(b, n) != 1)
    return false;
    Integer nminus1 = (n - 1);
    unsigned int a;
    // calculate a = largest power of 2 that divides (n-1)
    for (a = 0 ; ; a++)
    if (nminus1.GetBit(a))
    break;
    Integer m = nminus1 >> a;
    Integer z = a_exp_b_mod_c(b, m, n);
    if (z == 1 || z == nminus1)
    return true;
    for (unsigned j = 1 ; j < a ; j++)
    {
        z = z.Squared() % n;
        if (z == nminus1)
        return true;
        if (z == 1)
        return false;
    }
    return false;
}

bool RabinMillerTest(RandomNumberGenerator & rng, const Integer & n, unsigned int rounds)
{
    if (n <= 3)
    return n == 2 || n == 3;
    assert(n > 3);
    Integer b;
    for (unsigned int i = 0 ; i < rounds ; i++)
    {
        b.Randomize(rng, 2, n - 2);
        if (!IsStrongProbablePrime(n, b))
        return false;
    }
    return true;
}

bool IsLucasProbablePrime(const Integer & n)
{
    if (n <= 1)
    return false;
    if (n.IsEven())
    return n == 2;
    assert(n > 2);
    Integer b = 3;
    unsigned int i = 0;
    int j;
    while ((j = Jacobi(b.Squared() - 4, n)) == 1)
    {
        // avoid infinite loop if n is a square:
        if (++i == 64 && n.IsSquare())
        return false;
        ++b;
        ++b;
    }
    if (j == 0)
    return false;
    else
    return Lucas(n + 1, b, n) == 2;
}

bool IsStrongLucasProbablePrime(const Integer & n)
{
    if (n <= 1)
    return false;
    if (n.IsEven())
    return n == 2;
    assert(n > 2);
    Integer b = 3;
    unsigned int i = 0;
    int j;
    while ((j = Jacobi(b.Squared() - 4, n)) == 1)
    {
        // avoid infinite loop if n is a square:
        if (++i == 64 && n.IsSquare())
        return false;
        ++b;
        ++b;
    }
    if (j == 0)
    return false;
    Integer n1 = n + 1;
    unsigned int a;
    // calculate a = largest power of 2 that divides n1
    for (a = 0 ; ; a++)
    if (n1.GetBit(a))
    break;
    Integer m = n1 >> a;
    Integer z = Lucas(m, b, n);
    if (z == 2 || z == n - 2)
    return true;
    for (i = 1 ; i < a ; i++)
    {
        z = (z.Squared() - 2) % n;
        if (z == n - 2)
        return true;
        if (z == 2)
        return false;
    }
    return false;
}

bool IsPrime(const Integer & p)
{
    static const Integer lastSmallPrimeSquared = Integer(lastSmallPrime) .Squared();
    if (p <= lastSmallPrime)
    return IsSmallPrime(p);
    else if(p <= lastSmallPrimeSquared)
    return SmallDivisorsTest(p);
    else
    return SmallDivisorsTest(p) && IsStrongProbablePrime(p, 3) && IsStrongLucasProbablePrime(p);
}

bool VerifyPrime(RandomNumberGenerator & rng, const Integer & p, unsigned int level)
{
    bool pass = IsPrime(p) && RabinMillerTest(rng, p, 1);
    if (level >= 1)
    pass = pass && RabinMillerTest(rng, p, 10);
    return pass;
}

unsigned int PrimeSearchInterval(const Integer & max)
{
    return max.BitCount();
}

static inline bool FastProbablePrimeTest(const Integer & n)
{
    return IsStrongProbablePrime(n, 2);
}

AlgorithmParameters <AlgorithmParameters <AlgorithmParameters <NullNameValuePairs, Integer::RandomNumberType >, Integer >, Integer >
MakeParametersForTwoPrimesOfEqualSize(unsigned int productBitLength)
{
    if (productBitLength < 16)
    throw InvalidArgument("invalid bit length");
    Integer minP, maxP;
    if (productBitLength% 2 == 0)
    {
        minP = Integer(182) << (productBitLength/ 2 - 8);
        maxP = Integer::Power2(productBitLength/ 2) - 1;
    }
    else
    {
        minP = Integer::Power2((productBitLength - 1) / 2);
        maxP = Integer(181) << ((productBitLength + 1) / 2 - 8);
    }
    return MakeParameters("RandomNumberType", Integer::PRIME)("Min", minP)("Max", maxP);
}

class PrimeSieve
{
    public:
    // delta == 1 or -1 means double sieve with p = 2*q + delta
    PrimeSieve(const Integer & first, const Integer & last, const Integer & step, signed int delta = 0);
    bool NextCandidate(Integer & c);
    void DoSieve();
    static void SieveSingle(std::vector < bool > & sieve, word p, const Integer & first, const Integer & step, word stepInv);
    Integer m_first, m_last, m_step;
    signed int m_delta;
    word m_next;
    std::vector <bool > m_sieve;
};

PrimeSieve::PrimeSieve(const Integer & first, const Integer & last, const Integer & step, signed int delta)
: m_first(first), m_last(last), m_step(step), m_delta(delta), m_next(0)
{
    DoSieve();
}

bool PrimeSieve::NextCandidate(Integer & c)
{
    m_next = std::find(m_sieve.begin() + m_next, m_sieve.end(), false) - m_sieve.begin();
    if (m_next == m_sieve.size())
    {
        m_first += m_sieve.size() * m_step;
        if (m_first > m_last)
        return false;
        else
        {
            m_next = 0;
            DoSieve();
            return NextCandidate(c);
        }
    }
    else
    {
        c = m_first + m_next * m_step;
        ++m_next;
        return true;
    }
}

void PrimeSieve::SieveSingle(std::vector <bool > & sieve, word p, const Integer & first, const Integer & step, word stepInv)
{
    if (stepInv)
    {
        unsigned int sieveSize = sieve.size();
        word j = word((dword(p - (first% p)) * stepInv) % p);
        // if the first multiple of p is p, skip it
        if (first.WordCount() <= 1 && first + step * j == p)
        j += p;
        for ( ; j < sieveSize ; j += p)
        sieve[j] = true;
    }
}

void PrimeSieve::DoSieve()
{
    BuildPrimeTable();
    const unsigned int maxSieveSize = 32768;
    unsigned int sieveSize = STDMIN(Integer(maxSieveSize), (m_last - m_first) / m_step + 1) .ConvertToLong();
    m_sieve.clear();
    m_sieve.resize(sieveSize, false);
    if (m_delta == 0)
    {
        for (unsigned int i = 0 ; i < primeTableSize ;++i)
        SieveSingle(m_sieve, primeTable[i], m_first, m_step, m_step.InverseMod(primeTable[i]));
    }
    else
    {
        assert(m_step% 2 == 0);
        Integer qFirst = (m_first - m_delta) >> 1;
        Integer halfStep = m_step >> 1;
        for (unsigned int i = 0 ; i < primeTableSize ;++i)
        {
            word p = primeTable[i];
            word stepInv = m_step.InverseMod(p);
            SieveSingle(m_sieve, p, m_first, m_step, stepInv);
            word halfStepInv = 2 * stepInv <p ? 2 * stepInv: 2 * stepInv - p;
            SieveSingle(m_sieve, p, qFirst, halfStep, halfStepInv);
        }
    }
}

bool FirstPrime(Integer & p, const Integer & max, const Integer & equiv, const Integer & mod, const PrimeSelector * pSelector)
{
    assert(!equiv.IsNegative() && equiv < mod);
    Integer gcd = GCD(equiv, mod);
    if (gcd != Integer::One())
    {
        // the only possible prime p such that p%mod==equiv where GCD(mod,equiv)!=1 is GCD(mod,equiv)
        if (p <= gcd && gcd <= max && IsPrime(gcd))
        {
            p = gcd;
            return true;
        }
        else
        return false;
    }
    BuildPrimeTable();
    if (p <= primeTable[primeTableSize - 1])
    {
        word * pItr;
        --p;
        if (p.IsPositive())
        pItr = std::upper_bound(primeTable, primeTable + primeTableSize, (word) p.ConvertToLong());
        else
        pItr = primeTable;
        while (pItr < primeTable + primeTableSize && * pItr% mod != equiv)
        ++pItr;
        if (pItr < primeTable + primeTableSize)
        {
            p = * pItr;
            return p <= max;
        }
        p = primeTable[primeTableSize - 1] + 1;
    }
    assert(p > primeTable[primeTableSize - 1]);
    if (mod.IsOdd())
    return FirstPrime(p, max, CRT(equiv, mod, 1, 2, 1), mod << 1, pSelector);
    p += (equiv - p) % mod;
    if (p > max)
    return false;
    PrimeSieve sieve(p, max, mod);
    while (sieve.NextCandidate(p))
    {
        if ((!pSelector || pSelector->IsAcceptable(p)) && FastProbablePrimeTest(p) && IsPrime(p))
        return true;
    }
    return false;
}

// the following two functions are based on code and comments provided by Preda Mihailescu
static bool ProvePrime(const Integer & p, const Integer & q)
{
    assert(p < q * q * q);
    assert(p % q == 1);
    // this is the Quisquater test. Numbers p having passed the Lucas - Lehmer test
    // for q and verifying p < q^3 can only be built up of two factors, both = 1 mod q,
    // or be prime. The next two lines build the discriminant of a quadratic equation
    // which holds iff p is built up of two factors (excercise ... )
    Integer r = (p - 1) / q;
    if (((r% q) .Squared() - 4 * (r/ q)) .IsSquare())
    return false;
    assert(primeTableSize >= 50);
    for (int i = 0 ; i < 50 ; i++)
    {
        Integer b = a_exp_b_mod_c(primeTable[i], r, p);
        if (b != 1)
        return a_exp_b_mod_c(b, q, p) == 1;
    }
    return false;
}

Integer MihailescuProvablePrime(RandomNumberGenerator & rng, unsigned int pbits)
{
    Integer p;
    Integer minP = Integer::Power2(pbits - 1);
    Integer maxP = Integer::Power2(pbits) - 1;
    if (maxP <= Integer(lastSmallPrime) .Squared())
    {
        // Randomize() will generate a prime provable by trial division
        p.Randomize(rng, minP, maxP, Integer::PRIME);
        return p;
    }
    unsigned int qbits = (pbits + 2) / 3 + 1 + rng.GenerateWord32(0, pbits/ 36);
    Integer q = MihailescuProvablePrime(rng, qbits);
    Integer q2 = q <<1;
    while (true)
    {
        // this initializes the sieve to search in the arithmetic
        // progression p = p_0 + \lambda * q2 = p_0 + 2 * \lambda * q,
        // with q the recursively generated prime above. We will be able
        // to use Lucas tets for proving primality. A trick of Quisquater
        // allows taking q > cubic_root(p) rather then square_root: this
        // decreases the recursion.
        p.Randomize(rng, minP, maxP, Integer::ANY, 1, q2);
        PrimeSieve sieve(p, STDMIN(p + PrimeSearchInterval(maxP) * q2, maxP), q2);
        while (sieve.NextCandidate(p))
        {
            if (FastProbablePrimeTest(p) && ProvePrime(p, q))
            return p;
        }
    }
    // not reached
    return p;
}

Integer MaurerProvablePrime(RandomNumberGenerator & rng, unsigned int bits)
{
    const unsigned smallPrimeBound = 29, c_opt = 10;
    Integer p;
    BuildPrimeTable();
    if (bits < smallPrimeBound)
    {
        do
        p.Randomize(rng, Integer::Power2(bits - 1), Integer::Power2(bits) - 1, Integer::ANY, 1, 2);
        while (TrialDivision(p, 1 << ((bits + 1) / 2)));
    }
    else
    {
        const unsigned margin = bits > 50 ? 20: (bits - 10) / 2;
        double relativeSize;
        do
        relativeSize = pow(2.0, double(rng.GenerateWord32()) / 0xffffffff - 1);
        while (bits * relativeSize >= bits - margin);
        Integer a, b;
        Integer q = MaurerProvablePrime(rng, unsigned(bits * relativeSize));
        Integer I = Integer::Power2(bits - 2) / q;
        Integer I2 = I <<1;
        unsigned int trialDivisorBound = (unsigned int) STDMIN((unsigned long) primeTable[primeTableSize - 1], (unsigned long) bits * bits/ c_opt);
        bool success = false;
        while (!success)
        {
            p.Randomize(rng, I, I2, Integer::ANY);
            p *= q;
            p <<= 1;
            ++p;
            if (!TrialDivision(p, trialDivisorBound))
            {
                a.Randomize(rng, 2, p - 1, Integer::ANY);
                b = a_exp_b_mod_c(a, (p - 1) / q, p);
                success = (GCD(b - 1, p) == 1) && (a_exp_b_mod_c(b, q, p) == 1);
            }
        }
    }
    return p;
}

Integer CRT(const Integer & xp, const Integer & p, const Integer & xq, const Integer & q, const Integer & u)
{
    // isn't operator overloading great?
    return p * (u * (xq - xp) % q) + xp;
}

Integer CRT(const Integer & xp, const Integer & p, const Integer & xq, const Integer & q)
{
    return CRT(xp, p, xq, q, EuclideanMultiplicativeInverse(p, q));
}

Integer ModularSquareRoot(const Integer & a, const Integer & p)
{
    if (p% 4 == 3)
    return a_exp_b_mod_c(a, (p + 1) / 4, p);
    Integer q = p - 1;
    unsigned int r = 0;
    while (q.IsEven())
    {
        r++;
        q >>= 1;
    }
    Integer n = 2;
    while (Jacobi(n, p) != - 1)
    ++n;
    Integer y = a_exp_b_mod_c(n, q, p);
    Integer x = a_exp_b_mod_c(a, (q - 1) / 2, p);
    Integer b = (x.Squared() % p) * a% p;
    x = a * x% p;
    Integer tempb, t;
    while (b != 1)
    {
        unsigned m = 0;
        tempb = b;
        do
        {
            m++;
            b = b.Squared() % p;
            if (m == r)
            return Integer::Zero();
        }
        while (b != 1);
        t = y;
        for (unsigned i = 0 ; i < r - m - 1 ; i++)
        t = t.Squared() % p;
        y = t.Squared() % p;
        r = m;
        x = x * t% p;
        b = tempb * y% p;
    }
    assert(x.Squared() % p == a);
    return x;
}

bool SolveModularQuadraticEquation(Integer & r1, Integer & r2, const Integer & a, const Integer & b, const Integer & c, const Integer & p)
{
    Integer D = (b.Squared() - 4 * a * c) % p;
    switch (Jacobi(D, p))
    {
    default:
        assert(false);
        // not reached
        return false;
    case - 1:
        return false;
    case 0:
        r1 = r2 = ( - b * (a + a) .InverseMod(p)) % p;
        assert(((r1.Squared() * a + r1 * b + c) % p) .IsZero());
        return true;
    case 1:
        Integer s = ModularSquareRoot(D, p);
        Integer t = (a + a) .InverseMod(p);
        r1 = (s - b) * t % p;
        r2 = ( - s - b) * t % p;
        assert(((r1.Squared() * a + r1 * b + c) % p) .IsZero());
        assert(((r2.Squared() * a + r2 * b + c) % p) .IsZero());
        return true;
    }
}

Integer ModularRoot(const Integer & a, const Integer & dp, const Integer & dq,
const Integer & p, const Integer & q, const Integer & u)
{
    Integer p2 = ModularExponentiation((a % p), dp, p);
    Integer q2 = ModularExponentiation((a % q), dq, q);
    return CRT(p2, p, q2, q, u);
}

Integer ModularRoot(const Integer & a, const Integer & e,
const Integer & p, const Integer & q)
{
    Integer dp = EuclideanMultiplicativeInverse(e, p - 1);
    Integer dq = EuclideanMultiplicativeInverse(e, q - 1);
    Integer u = EuclideanMultiplicativeInverse(p, q);
    assert(! !dp && ! !dq && ! !u);
    return ModularRoot(a, dp, dq, p, q, u);
}

 /*
 Integer GCDI(const Integer &x, const Integer &y)
 {
 Integer a=x, b=y;
 unsigned k=0;
 assert(!!a && !!b);
 while (a[0]==0 && b[0]==0)
 {
 a >>= 1;
 b >>= 1;
 k++;
 }
 while (a[0]==0)
 a >>= 1;
 while (b[0]==0)
 b >>= 1;
 while (1)
 {
 switch (a.Compare(b))
 {
 case -1:
 b -= a;
 while (b[0]==0)
 b >>= 1;
 break;
 case 0:
 return (a <<= k);
 case 1:
 a -= b;
 while (a[0]==0)
 a >>= 1;
 break;
 default:
 assert(false);
 }
 }
 }
 Integer EuclideanMultiplicativeInverse(const Integer &a, const Integer &b)
 {
 assert(b.Positive());
 if (a.Negative())
 return EuclideanMultiplicativeInverse(a%b, b);
 if (b[0]==0)
 {
 if (!b || a[0]==0)
 return Integer::Zero();       // no inverse
 if (a==1)
 return 1;
 Integer u = EuclideanMultiplicativeInverse(b, a);
 if (!u)
 return Integer::Zero();       // no inverse
 else
 return (b*(a-u)+1)/a;
 }
 Integer u=1, d=a, v1=b, v3=b, t1, t3, b2=(b+1)>>1;
 if (a[0])
 {
 t1 = Integer::Zero();
 t3 = -b;
 }
 else
 {
 t1 = b2;
 t3 = a>>1;
 }
 while (!!t3)
 {
 while (t3[0]==0)
 {
 t3 >>= 1;
 if (t1[0]==0)
 t1 >>= 1;
 else
 {
 t1 >>= 1;
 t1 += b2;
 }
 }
 if (t3.Positive())
 {
 u = t1;
 d = t3;
 }
 else
 {
 v1 = b-t1;
 v3 = -t3;
 }
 t1 = u-v1;
 t3 = d-v3;
 if (t1.Negative())
 t1 += b;
 }
 if (d==1)
 return u;
 else
 return Integer::Zero();   // no inverse
 }
    */

int Jacobi(const Integer & aIn, const Integer & bIn)
{
    assert(bIn.IsOdd());
    Integer b = bIn, a = aIn% bIn;
    int result = 1;
    while (! !a)
    {
        unsigned i = 0;
        while (a.GetBit(i) == 0)
        i++;
        a >>= i;
        if (i% 2 == 1 && (b% 8 == 3 || b% 8 == 5))
        result = - result;
        if (a% 4 == 3 && b% 4 == 3)
        result = - result;
        std::swap(a, b);
        a %= b;
    }
    return(b == 1) ? result: 0;
}

Integer Lucas(const Integer & e, const Integer & pIn, const Integer & n)
{
    unsigned i = e.BitCount();
    if (i == 0)
    return Integer::Two();
    MontgomeryRepresentation m(n);
    Integer p = m.ConvertIn(pIn% n), two = m.ConvertIn(Integer::Two());
    Integer v = p, v1 = m.Subtract(m.Square(p), two);
    i--;
    while (i--)
    {
        if (e.GetBit(i))
        {
            // v = (v*v1 - p) % m;
            v = m.Subtract(m.Multiply(v, v1), p);
            // v1 = (v1*v1 - 2) % m;
            v1 = m.Subtract(m.Square(v1), two);
        }
        else
        {
            // v1 = (v*v1 - p) % m;
            v1 = m.Subtract(m.Multiply(v, v1), p);
            // v = (v*v - 2) % m;
            v = m.Subtract(m.Square(v), two);
        }
    }
    return m.ConvertOut(v);
}

// This is Peter Montgomery's unpublished Lucas sequence evalutation algorithm.
// The total number of multiplies and squares used is less than the binary
// algorithm (see above).  Unfortunately I can't get it to run as fast as
// the binary algorithm because of the extra overhead.
 /*
 Integer Lucas(const Integer &n, const Integer &P, const Integer &modulus)
 {
 if (!n)
 return 2;
 #define f(A, B, C)	m.Subtract(m.Multiply(A, B), C)
 #define X2(A) m.Subtract(m.Square(A), two)
 #define X3(A) m.Multiply(A, m.Subtract(m.Square(A), three))
 MontgomeryRepresentation m(modulus);
 Integer two=m.ConvertIn(2), three=m.ConvertIn(3);
 Integer A=m.ConvertIn(P), B, C, p, d=n, e, r, t, T, U;
 while (d!=1)
 {
 p = d;
 unsigned int b = WORD_BITS * p.WordCount();
 Integer alpha = (Integer(5)<<(2*b-2)).SquareRoot() - Integer::Power2(b-1);
 r = (p*alpha)>>b;
 e = d-r;
 B = A;
 C = two;
 d = r;
 while (d!=e)
 {
 if (d<e)
 {
 swap(d, e);
 swap(A, B);
 }
 unsigned int dm2 = d[0], em2 = e[0];
 unsigned int dm3 = d%3, em3 = e%3;
 //			if ((dm6+em6)%3 == 0 && d <= e + (e>>2))
 if ((dm3+em3==0 || dm3+em3==3) && (t = e, t >>= 2, t += e, d <= t))
 {
 // #1
 //				t = (d+d-e)/3;
 //				t = d; t += d; t -= e; t /= 3;
 //				e = (e+e-d)/3;
 //				e += e; e -= d; e /= 3;
 //				d = t;
 //				t = (d+e)/3
 t = d; t += e; t /= 3;
 e -= t;
 d -= t;
 T = f(A, B, C);
 U = f(T, A, B);
 B = f(T, B, A);
 A = U;
 continue;
 }
 //			if (dm6 == em6 && d <= e + (e>>2))
 if (dm3 == em3 && dm2 == em2 && (t = e, t >>= 2, t += e, d <= t))
 {
 // #2
 //				d = (d-e)>>1;
 d -= e; d >>= 1;
 B = f(A, B, C);
 A = X2(A);
 continue;
 }
 //			if (d <= (e<<2))
 if (d <= (t = e, t <<= 2))
 {
 // #3
 d -= e;
 C = f(A, B, C);
 swap(B, C);
 continue;
 }
 if (dm2 == em2)
 {
 // #4
 //				d = (d-e)>>1;
 d -= e; d >>= 1;
 B = f(A, B, C);
 A = X2(A);
 continue;
 }
 if (dm2 == 0)
 {
 // #5
 d >>= 1;
 C = f(A, C, B);
 A = X2(A);
 continue;
 }
 if (dm3 == 0)
 {
 // #6
 //				d = d/3 - e;
 d /= 3; d -= e;
 T = X2(A);
 C = f(T, f(A, B, C), C);
 swap(B, C);
 A = f(T, A, A);
 continue;
 }
 if (dm3+em3==0 || dm3+em3==3)
 {
 // #7
 //				d = (d-e-e)/3;
 d -= e; d -= e; d /= 3;
 T = f(A, B, C);
 B = f(T, A, B);
 A = X3(A);
 continue;
 }
 if (dm3 == em3)
 {
 // #8
 //				d = (d-e)/3;
 d -= e; d /= 3;
 T = f(A, B, C);
 C = f(A, C, B);
 B = T;
 A = X3(A);
 continue;
 }
 assert(em2 == 0);
 // #9
 e >>= 1;
 C = f(C, B, A);
 B = X2(B);
 }
 A = f(A, B, C);
 }
 #undef f
 #undef X2
 #undef X3
 return m.ConvertOut(A);
 }
    */

unsigned int FactoringWorkFactor(unsigned int n)
{
    // extrapolated from the table in Odlyzko's "The Future of Integer Factorization"
    // updated to reflect the factoring of RSA-130
    if (n < 5) return 0;
    else return(unsigned int)(2.4 * pow((double) n, 1.0/ 3.0) * pow(log(double(n)), 2.0/ 3.0) - 5);
}

unsigned int DiscreteLogWorkFactor(unsigned int n)
{
    // assuming discrete log takes about the same time as factoring
    if (n < 5) return 0;
    else return(unsigned int)(2.4 * pow((double) n, 1.0/ 3.0) * pow(log(double(n)), 2.0/ 3.0) - 5);
}

// ********************************************************

void PrimeAndGenerator::Generate(signed int delta, RandomNumberGenerator & rng, unsigned int pbits, unsigned int qbits)
{
    // no prime exists for delta = -1, qbits = 4, and pbits = 5
    assert(qbits > 4);
    assert(pbits > qbits);
    if (qbits + 1 == pbits)
    {
        Integer minP = Integer::Power2(pbits - 1);
        Integer maxP = Integer::Power2(pbits) - 1;
        bool success = false;
        while (!success)
        {
            p.Randomize(rng, minP, maxP, Integer::ANY, 6 + 5 * delta, 12);
            PrimeSieve sieve(p, STDMIN(p + PrimeSearchInterval(maxP) * 12, maxP), 12, delta);
            while (sieve.NextCandidate(p))
            {
                assert(IsSmallPrime(p) || SmallDivisorsTest(p));
                q = (p - delta) >> 1;
                assert(IsSmallPrime(q) || SmallDivisorsTest(q));
                if (FastProbablePrimeTest(q) && FastProbablePrimeTest(p) && IsPrime(q) && IsPrime(p))
                {
                    success = true;
                    break;
                }
            }
        }
        if (delta == 1)
        {
            // find g such that g is a quadratic residue mod p, then g has order q
            // g=4 always works, but this way we get the smallest quadratic residue (other than 1)
            for (g = 2 ; Jacobi(g, p) != 1 ;++g)
            {
            }
            // contributed by Walt Tuvell: g should be the following according to the Law of Quadratic Reciprocity
            assert((p% 8 == 1 || p% 8 == 7) ? g == 2: (p% 12 == 1 || p% 12 == 11) ? g == 3: g == 4);
        }
        else
        {
            assert(delta == - 1);
            // find g such that g*g-4 is a quadratic non-residue,
            // and such that g has order q
            for (g = 3 ; ;++g)
            if (Jacobi(g * g - 4, p) == - 1 && Lucas(q, g, p) == 2)
            break;
        }
    }
    else
    {
        Integer minQ = Integer::Power2(qbits - 1);
        Integer maxQ = Integer::Power2(qbits) - 1;
        Integer minP = Integer::Power2(pbits - 1);
        Integer maxP = Integer::Power2(pbits) - 1;
        do
        {
            q.Randomize(rng, minQ, maxQ, Integer::PRIME);
        }
        while (!p.Randomize(rng, minP, maxP, Integer::PRIME, delta% q, q));
        // find a random g of order q
        if (delta == 1)
        {
            do
            {
                Integer h(rng, 2, p - 2, Integer::ANY);
                g = a_exp_b_mod_c(h, (p - 1) / q, p);
            }
            while (g <= 1);
            assert(a_exp_b_mod_c(g, q, p) == 1);
        }
        else
        {
            assert(delta == - 1);
            do
            {
                Integer h(rng, 3, p - 1, Integer::ANY);
                if (Jacobi(h * h - 4, p) == 1)
                continue;
                g = Lucas((p + 1) / q, h, p);
            }
            while (g <= 2);
            assert(Lucas(q, g, p) == 2);
        }
    }
}

// oaep.cpp - written and placed in the public domain by Wei Dai

// ********************************************************

namespace
{
    template <class H, byte * P, unsigned int PLen >
    struct PHashComputation
    {
        PHashComputation()
        {
            H() .CalculateDigest(pHash, P, PLen);
        }
        byte pHash[H::DIGESTSIZE];
        };
    template <class H, byte * P, unsigned int PLen >
    const byte * PHash()
    {
        static PHashComputation <H, P, PLen > pHash;
        return pHash.pHash;
    }
}

template <class H, class MGF, byte * P, unsigned int PLen >
unsigned int OAEP <H, MGF, P, PLen >::MaxUnpaddedLength(unsigned int paddedLength) const
{
    return paddedLength/ 8 > 1 + 2 * H::DIGESTSIZE ? paddedLength/ 8 - 1 - 2 * H::DIGESTSIZE: 0;
}

template <class H, class MGF, byte * P, unsigned int PLen >
void OAEP <H, MGF, P, PLen >::Pad(RandomNumberGenerator & rng, const byte * input, unsigned int inputLength, byte * oaepBlock, unsigned int oaepBlockLen) const
{
    assert(inputLength <= MaxUnpaddedLength(oaepBlockLen));
    // convert from bit length to byte length
    if (oaepBlockLen % 8 != 0)
    {
        oaepBlock[0] = 0;
        oaepBlock++;
    }
    oaepBlockLen /= 8;
    const unsigned int hLen = H::DIGESTSIZE;
    const unsigned int seedLen = hLen, dbLen = oaepBlockLen - seedLen;
    byte * const maskedSeed = oaepBlock;
    byte * const maskedDB = oaepBlock + seedLen;
    // DB = pHash || 00 ... || 01 || M
    memcpy(maskedDB, PHash < H, P, PLen > (), hLen);
    memset(maskedDB + hLen, 0, dbLen - hLen - inputLength - 1);
    maskedDB[dbLen - inputLength - 1] = 0x01;
    memcpy(maskedDB + dbLen - inputLength, input, inputLength);
    rng.GenerateBlock(maskedSeed, seedLen);
    H h;
    MGF mgf;
    mgf.GenerateAndMask(h, maskedDB, dbLen, maskedSeed, seedLen);
    mgf.GenerateAndMask(h, maskedSeed, seedLen, maskedDB, dbLen);
}

template <class H, class MGF, byte * P, unsigned int PLen >
DecodingResult OAEP <H, MGF, P, PLen >::Unpad(const byte * oaepBlock, unsigned int oaepBlockLen, byte * output) const
{
    bool invalid = false;
    // convert from bit length to byte length
    if (oaepBlockLen % 8 != 0)
    {
        invalid = (oaepBlock[0] != 0) || invalid;
        oaepBlock++;
    }
    oaepBlockLen /= 8;
    const unsigned int hLen = H::DIGESTSIZE;
    const unsigned int seedLen = hLen, dbLen = oaepBlockLen - seedLen;
    invalid = (oaepBlockLen < 2 * hLen + 1) || invalid;
    SecByteBlock t(oaepBlock, oaepBlockLen);
    byte * const maskedSeed = t;
    byte * const maskedDB = t + seedLen;
    H h;
    MGF mgf;
    mgf.GenerateAndMask(h, maskedSeed, seedLen, maskedDB, dbLen);
    mgf.GenerateAndMask(h, maskedDB, dbLen, maskedSeed, seedLen);
    // DB = pHash' || 00 ... || 01 || M
    byte * M = std::find(maskedDB + hLen, maskedDB + dbLen, 0x01);
    invalid = (M == maskedDB + dbLen) || invalid;
    invalid = (std::find_if(maskedDB + hLen, M, std::bind2nd(std::not_equal_to < byte > (), 0)) != M) || invalid;
    invalid = (memcmp(maskedDB, PHash < H, P, PLen > (), hLen) != 0) || invalid;
    if (invalid)
    return DecodingResult();
    M++;
    memcpy(output, M, maskedDB + dbLen - M);
    return DecodingResult(maskedDB + dbLen - M);
}

// pkcspad.cpp - written and placed in the public domain by Wei Dai

template <> const byte PKCS_DigestDecoration <SHA >::decoration[] =
{
    0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A, 0x05, 0x00, 0x04, 0x14
};

template <> const unsigned int PKCS_DigestDecoration <SHA >::length = sizeof(PKCS_DigestDecoration <SHA >::decoration);

unsigned int PKCS_EncryptionPaddingScheme::MaxUnpaddedLength(unsigned int paddedLength) const
{
    return SaturatingSubtract(paddedLength/ 8, 10U);
}

void PKCS_EncryptionPaddingScheme::Pad(RandomNumberGenerator & rng, const byte * input, unsigned int inputLen, byte * pkcsBlock, unsigned int pkcsBlockLen) const
{
    assert(inputLen <= MaxUnpaddedLength(pkcsBlockLen));
    // this should be checked by caller
    // convert from bit length to byte length
    if (pkcsBlockLen % 8 != 0)
    {
        pkcsBlock[0] = 0;
        pkcsBlock++;
    }
    pkcsBlockLen /= 8;
    pkcsBlock[0] = 2;
    // block type 2
    // pad with non-zero random bytes
    for (unsigned i = 1 ; i < pkcsBlockLen - inputLen - 1 ; i++)
    pkcsBlock[i] = (byte) rng.GenerateWord32(1, 0xff);
    pkcsBlock[pkcsBlockLen - inputLen - 1] = 0;
    // separator
    memcpy(pkcsBlock + pkcsBlockLen - inputLen, input, inputLen);
}

DecodingResult PKCS_EncryptionPaddingScheme::Unpad(const byte * pkcsBlock, unsigned int pkcsBlockLen, byte * output) const
{
    bool invalid = false;
    unsigned int maxOutputLen = MaxUnpaddedLength(pkcsBlockLen);
    // convert from bit length to byte length
    if (pkcsBlockLen % 8 != 0)
    {
        invalid = (pkcsBlock[0] != 0) || invalid;
        pkcsBlock++;
    }
    pkcsBlockLen /= 8;
    // Require block type 2.
    invalid = (pkcsBlock[0] != 2) || invalid;
    // skip past the padding until we find the separator
    unsigned i = 1;
    while (i < pkcsBlockLen && pkcsBlock[i])
    {
        i++;
    }
    assert(i == pkcsBlockLen || pkcsBlock[i - 1] == 0);
    unsigned int outputLen = pkcsBlockLen - i;
    invalid = (outputLen > maxOutputLen) || invalid;
    if (invalid)
    return DecodingResult();
    memcpy(output, pkcsBlock + i, outputLen);
    return DecodingResult(outputLen);
}

// ********************************************************

void PKCS1v15_SignatureMessageEncodingMethod::xmCMR(RandomNumberGenerator & rng,
const byte * recoverableMessage, unsigned int recoverableMessageLength,
HashTransformation & hash, HashIdentifier hashIdentifier, bool messageEmpty,
byte * representative, unsigned int representativeBitLength) const
{
    unsigned int digestSize = hash.DigestSize();
    unsigned char * u;
    u = (unsigned char *) representative;
    if (digestSize + hashIdentifier.second + 10 > representativeBitLength/ 8)
    throw PK_Signer::KeyTooShort();
    unsigned int pkcsBlockLen = representativeBitLength;
    // convert from bit length to byte length
    if (pkcsBlockLen % 8 != 0)
    {
        representative[0] = 0;
        representative++;
    }
    pkcsBlockLen /= 8;
    representative[0] = 1;
    // block type 1
    byte * pPadding = representative + 1;
    byte * pDigest = representative + pkcsBlockLen - digestSize;
    byte * pHashId = pDigest - hashIdentifier.second;
    byte * pSeparator = pHashId - 1;
    // pad with 0xff
    memset(pPadding, 0xff, pSeparator - pPadding);
    * pSeparator = 0;
    memcpy(pHashId, hashIdentifier.first, hashIdentifier.second);
    hash.xmTF(pDigest, hash.DigestSize());
}

// pubkey.cpp - written and placed in the public domain by Wei Dai

void P1363_MGF1KDF2_Common(HashTransformation & hash, byte * output, unsigned int outputLength, const byte * input, unsigned int inputLength, bool mask, unsigned int counterStart)
{
    ArraySink * sink;
    HashFilter filter(hash, sink = mask ? new ArrayXorSink(output, outputLength): new ArraySink(output, outputLength));
    word32 counter = counterStart;
    while (sink->AvailableSize() > 0)
    {
        filter.Put(input, inputLength);
        filter.PutWord32(counter++);
        filter.MessageEnd();
    }
}

bool PK_DeterministicSignatureMessageEncodingMethod::xmVMR(
HashTransformation & hash, HashIdentifier hashIdentifier, bool messageEmpty,
byte * representative, unsigned int representativeBitLength) const
{
    SecByteBlock computedRepresentative(BitsToBytes(representativeBitLength));
    xmCMR(NullRNG(), NULL, 0, hash, hashIdentifier, messageEmpty, computedRepresentative, representativeBitLength);
    return memcmp(representative, computedRepresentative, computedRepresentative.size()) == 0;
}

unsigned int TF_SignerBase::SignAndRestart(RandomNumberGenerator & rng, PK_MessageAccumulator & messageAccumulator, byte * signature, bool restart) const
{
    PK_MessageAccumulatorBase & ma = static_cast <PK_MessageAccumulatorBase &> (messageAccumulator);
    SecByteBlock representative(MessageRepresentativeLength());
    GetMessageEncodingInterface() .xmCMR(rng,
    ma.m_recoverableMessage, ma.m_recoverableMessage.size(),
    ma.AccessHash(), GetHashIdentifier(), ma.m_empty,
    representative, MessageRepresentativeBitLength());
    ma.m_empty = true;
    Integer r(representative, representative.size());
    unsigned int signatureLength = SignatureLength();
    GetTrapdoorFunctionInterface() .CalculateRandomizedInverse(rng, r) .Encode(signature, signatureLength);
    return signatureLength;
}

void TF_VerifierBase::InputSignature(PK_MessageAccumulator & messageAccumulator, const byte * signature, unsigned int signatureLength) const
{
    PK_MessageAccumulatorBase & ma = static_cast <PK_MessageAccumulatorBase &> (messageAccumulator);
    ma.m_representative.New(MessageRepresentativeLength());
    Integer x = GetTrapdoorFunctionInterface() .ApplyFunction(Integer(signature, signatureLength));
    if (x.BitCount() > MessageRepresentativeBitLength())
    x = Integer::Zero();
    // don't return false here to prevent timing attack
    x.Encode(ma.m_representative, ma.m_representative.size());
}

bool TF_VerifierBase::VerifyAndRestart(PK_MessageAccumulator & messageAccumulator) const
{
    PK_MessageAccumulatorBase & ma = static_cast <PK_MessageAccumulatorBase &> (messageAccumulator);
    bool result = GetMessageEncodingInterface() .xmVMR(
    ma.AccessHash(), GetHashIdentifier(), ma.m_empty, ma.m_representative, MessageRepresentativeBitLength());
    ma.m_empty = true;
    return result;
}

DecodingResult TF_VerifierBase::RecoverAndRestart(byte * recoveredMessage, PK_MessageAccumulator & messageAccumulator) const
{
    PK_MessageAccumulatorBase & ma = static_cast <PK_MessageAccumulatorBase &> (messageAccumulator);
    DecodingResult result = GetMessageEncodingInterface() .RecoverMessageFromRepresentative(
    ma.AccessHash(), GetHashIdentifier(), ma.m_empty, ma.m_representative, MessageRepresentativeBitLength(), recoveredMessage);
    ma.m_empty = true;
    return result;
}

DecodingResult TF_DecryptorBase::FixedLengthDecrypt(RandomNumberGenerator & rng, const byte * cipherText, byte * plainText) const
{
    SecByteBlock paddedBlock(PaddedBlockByteLength());
    Integer x = GetTrapdoorFunctionInterface() .CalculateInverse(rng, Integer(cipherText, FixedCiphertextLength()));
    if (x.ByteCount() > paddedBlock.size())
    x = Integer::Zero();
    // don't return false here to prevent timing attack
    x.Encode(paddedBlock, paddedBlock.size());
    return GetMessageEncodingInterface() .Unpad(paddedBlock, PaddedBlockBitLength(), plainText);
}

void TF_EncryptorBase::Encrypt(RandomNumberGenerator & rng, const byte * plainText, unsigned int plainTextLength, byte * cipherText) const
{
    if (plainTextLength > FixedMaxPlaintextLength())
    throw InvalidArgument(AlgorithmName() + ": message too long for this public key");
    SecByteBlock paddedBlock(PaddedBlockByteLength());
    GetMessageEncodingInterface() .Pad(rng, plainText, plainTextLength, paddedBlock, PaddedBlockBitLength());
    GetTrapdoorFunctionInterface() .ApplyRandomizedFunction(rng, Integer(paddedBlock, paddedBlock.size())) .Encode(cipherText, FixedCiphertextLength());
}

// queue.cpp - written and placed in the public domain by Wei Dai

// this class for use by ByteQueue only
class ByteQueueNode
{
    public:
    ByteQueueNode(unsigned int maxSize)
    : buf(maxSize)
    {
        m_head = m_tail = 0;
        next = 0;
    }
    inline unsigned int MaxSize() const
    {
        return buf.size();
    }
    inline unsigned int CurrentSize() const
    {
        return m_tail - m_head;
    }
    inline bool UsedUp() const
    {
        return(m_head == MaxSize());
    }
    inline void Clear()
    {
        m_head = m_tail = 0;
    }
 /*	inline unsigned int Put(byte inByte)
 {
 if (MaxSize()==m_tail)
 return 0;
 buf[m_tail++]=inByte;
 return 1;
 }
    */
    inline unsigned int Put(const byte * begin, unsigned int length)
    {
        unsigned int l = STDMIN(length, MaxSize() - m_tail);
        memcpy(buf + m_tail, begin, l);
        m_tail += l;
        return l;
    }
    inline unsigned int Peek(byte & outByte) const
    {
        if (m_tail == m_head)
        return 0;
        outByte = buf[m_head];
        return 1;
    }
    inline unsigned int Peek(byte * target, unsigned int copyMax) const
    {
        unsigned int len = STDMIN(copyMax, m_tail - m_head);
        memcpy(target, buf + m_head, len);
        return len;
    }
    inline unsigned int CopyTo(BufferedTransformation & target, const std::string & channel = BufferedTransformation::NULL_CHANNEL) const
    {
        unsigned int len = m_tail - m_head;
        target.ChannelPut(channel, buf + m_head, len);
        return len;
    }
    inline unsigned int CopyTo(BufferedTransformation & target, unsigned int copyMax, const std::string & channel = BufferedTransformation::NULL_CHANNEL) const
    {
        unsigned int len = STDMIN(copyMax, m_tail - m_head);
        target.ChannelPut(channel, buf + m_head, len);
        return len;
    }
    inline unsigned int Get(byte & outByte)
    {
        unsigned int len = Peek(outByte);
        m_head += len;
        return len;
    }
    inline unsigned int Get(byte * outString, unsigned int getMax)
    {
        unsigned int len = Peek(outString, getMax);
        m_head += len;
        return len;
    }
    inline unsigned int TransferTo(BufferedTransformation & target, const std::string & channel = BufferedTransformation::NULL_CHANNEL)
    {
        unsigned int len = m_tail - m_head;
        target.ChannelPutModifiable(channel, buf + m_head, len);
        m_head = m_tail;
        return len;
    }
    inline unsigned int TransferTo(BufferedTransformation & target, unsigned int transferMax, const std::string & channel = BufferedTransformation::NULL_CHANNEL)
    {
        unsigned int len = STDMIN(transferMax, m_tail - m_head);
        target.ChannelPutModifiable(channel, buf + m_head, len);
        m_head += len;
        return len;
    }
    inline unsigned int Skip(unsigned int skipMax)
    {
        unsigned int len = STDMIN(skipMax, m_tail - m_head);
        m_head += len;
        return len;
    }
    inline byte operator[] (unsigned int i) const
    {
        return buf[m_head + i];
    }
    ByteQueueNode * next;
    SecByteBlock buf;
    unsigned int m_head, m_tail;
};

// ********************************************************

ByteQueue::ByteQueue(unsigned int m_nodeSize)
: m_nodeSize(m_nodeSize), m_lazyLength(0)
{
    m_head = m_tail = new ByteQueueNode(m_nodeSize);
}

ByteQueue::ByteQueue(const ByteQueue & copy)
{
    CopyFrom(copy);
}

void ByteQueue::CopyFrom(const ByteQueue & copy)
{
    m_lazyLength = 0;
    m_nodeSize = copy.m_nodeSize;
    m_head = m_tail = new ByteQueueNode( * copy.m_head);
    for (ByteQueueNode * current = copy.m_head->next ; current ; current = current->next)
    {
        m_tail->next = new ByteQueueNode( * current);
        m_tail = m_tail->next;
    }
    m_tail->next = NULL;
    Put(copy.m_lazyString, copy.m_lazyLength);
}

ByteQueue::~ ByteQueue()
{
    Destroy();
}

void ByteQueue::Destroy()
{
    ByteQueueNode * next;
    for (ByteQueueNode * current = m_head ; current ; current = next)
    {
        next = current->next;
        delete current;
    }
}

void ByteQueue::IsolatedInitialize(const NameValuePairs & parameters)
{
    m_nodeSize = parameters.GetIntValueWithDefault("NodeSize", 256);
    Clear();
}

unsigned long ByteQueue::CurrentSize() const
{
    unsigned long size = 0;
    for (ByteQueueNode * current = m_head ; current ; current = current->next)
    size += current->CurrentSize();
    return size + m_lazyLength;
}

bool ByteQueue::IsEmpty() const
{
    return m_head == m_tail && m_head->CurrentSize() == 0 && m_lazyLength == 0;
}

void ByteQueue::Clear()
{
    Destroy();
    m_head = m_tail = new ByteQueueNode(m_nodeSize);
    m_lazyLength = 0;
}

unsigned int ByteQueue::Put2(const byte * inString, unsigned int length, int messageEnd, bool blocking)
{
    if (m_lazyLength > 0)
    FinalizeLazyPut();
    unsigned int len;
    while ((len = m_tail->Put(inString, length)) < length)
    {
        m_tail->next = new ByteQueueNode(m_nodeSize);
        m_tail = m_tail->next;
        inString += len;
        length -= len;
    }
    return 0;
}

void ByteQueue::CleanupUsedNodes()
{
    while (m_head != m_tail && m_head->UsedUp())
    {
        ByteQueueNode * temp = m_head;
        m_head = m_head->next;
        delete temp;
    }
    if (m_head->CurrentSize() == 0)
    m_head->Clear();
}

void ByteQueue::LazyPut(const byte * inString, unsigned int size)
{
    if (m_lazyLength > 0)
    FinalizeLazyPut();
    m_lazyString = inString;
    m_lazyLength = size;
}

void ByteQueue::UndoLazyPut(unsigned int size)
{
    if (m_lazyLength < size)
    throw InvalidArgument("ByteQueue: size specified for UndoLazyPut is too large");
    m_lazyLength -= size;
}

void ByteQueue::FinalizeLazyPut()
{
    unsigned int len = m_lazyLength;
    m_lazyLength = 0;
    if (len)
    Put(m_lazyString, len);
}

unsigned int ByteQueue::Get(byte & outByte)
{
    if (m_head->Get(outByte))
    {
        if (m_head->UsedUp())
        CleanupUsedNodes();
        return 1;
    }
    else if(m_lazyLength > 0)
    {
        outByte = * m_lazyString++;
        m_lazyLength--;
        return 1;
    }
    else
    return 0;
}

unsigned int ByteQueue::Get(byte * outString, unsigned int getMax)
{
    ArraySink sink(outString, getMax);
    return TransferTo(sink, getMax);
}

unsigned int ByteQueue::Peek(byte & outByte) const
{
    if (m_head->Peek(outByte))
    return 1;
    else if(m_lazyLength > 0)
    {
        outByte = * m_lazyString;
        return 1;
    }
    else
    return 0;
}

unsigned int ByteQueue::Peek(byte * outString, unsigned int peekMax) const
{
    ArraySink sink(outString, peekMax);
    return CopyTo(sink, peekMax);
}

unsigned int ByteQueue::TransferTo2(BufferedTransformation & target, unsigned long & transferBytes, const std::string & channel, bool blocking)
{
    if (blocking)
    {
        unsigned long bytesLeft = transferBytes;
        for (ByteQueueNode * current = m_head ; bytesLeft && current ; current = current->next)
        bytesLeft -= current->TransferTo(target, bytesLeft, channel);
        CleanupUsedNodes();
        unsigned int len = (unsigned int) STDMIN(bytesLeft, (unsigned long) m_lazyLength);
        if (len)
        {
            target.ChannelPut(channel, m_lazyString, len);
            m_lazyString += len;
            m_lazyLength -= len;
            bytesLeft -= len;
        }
        transferBytes -= bytesLeft;
        return 0;
    }
    else
    {
        Walker walker( * this);
        unsigned int blockedBytes = walker.TransferTo2(target, transferBytes, channel, blocking);
        Skip(transferBytes);
        return blockedBytes;
    }
}

unsigned int ByteQueue::CopyRangeTo2(BufferedTransformation & target, unsigned long & begin, unsigned long end, const std::string & channel, bool blocking) const
{
    Walker walker( * this);
    walker.Skip(begin);
    unsigned long transferBytes = end - begin;
    unsigned int blockedBytes = walker.TransferTo2(target, transferBytes, channel, blocking);
    begin += transferBytes;
    return blockedBytes;
}

void ByteQueue::Unget(byte inByte)
{
    Unget( & inByte, 1);
}

void ByteQueue::Unget(const byte * inString, unsigned int length)
{
    // TODO: make this more efficient
    ByteQueueNode * newHead = new ByteQueueNode(length);
    newHead->next = m_head;
    m_head = newHead;
    m_head->Put(inString, length);
}

const byte * ByteQueue::Spy(unsigned int & contiguousSize) const
{
    contiguousSize = m_head->m_tail - m_head->m_head;
    if (contiguousSize == 0 && m_lazyLength > 0)
    {
        contiguousSize = m_lazyLength;
        return m_lazyString;
    }
    else
    return m_head->buf + m_head->m_head;
}

byte * ByteQueue::CreatePutSpace(unsigned int & size)
{
    if (m_lazyLength > 0)
    FinalizeLazyPut();
    if (m_tail->m_tail == m_tail->MaxSize())
    {
        m_tail->next = new ByteQueueNode(size < m_nodeSize ? m_nodeSize: STDMAX(m_nodeSize, 1024U));
        m_tail = m_tail->next;
    }
    size = m_tail->MaxSize() - m_tail->m_tail;
    return m_tail->buf + m_tail->m_tail;
}

ByteQueue & ByteQueue::operator = (const ByteQueue & rhs)
{
    Destroy();
    CopyFrom(rhs);
    return * this;
}

bool ByteQueue::operator == (const ByteQueue & rhs) const
{
    const unsigned long currentSize = CurrentSize();
    if (currentSize != rhs.CurrentSize())
    return false;
    Walker walker1( * this), walker2(rhs);
    byte b1, b2;
    while (walker1.Get(b1) && walker2.Get(b2))
    if (b1 != b2)
    return false;
    return true;
}

byte ByteQueue::operator[] (unsigned long i) const
{
    for (ByteQueueNode * current = m_head ; current ; current = current->next)
    {
        if (i < current->CurrentSize())
        return( * current) [i];
        i -= current->CurrentSize();
    }
    assert(i < m_lazyLength);
    return m_lazyString[i];
}

void ByteQueue::swap(ByteQueue & rhs)
{
    std::swap(m_nodeSize, rhs.m_nodeSize);
    std::swap(m_head, rhs.m_head);
    std::swap(m_tail, rhs.m_tail);
    std::swap(m_lazyString, rhs.m_lazyString);
    std::swap(m_lazyLength, rhs.m_lazyLength);
}

// ********************************************************

void ByteQueue::Walker::IsolatedInitialize(const NameValuePairs & parameters)
{
    m_node = m_queue.m_head;
    m_position = 0;
    m_offset = 0;
    m_lazyString = m_queue.m_lazyString;
    m_lazyLength = m_queue.m_lazyLength;
}

unsigned int ByteQueue::Walker::Get(byte & outByte)
{
    ArraySink sink( & outByte, 1);
    return TransferTo(sink, 1);
}

unsigned int ByteQueue::Walker::Get(byte * outString, unsigned int getMax)
{
    ArraySink sink(outString, getMax);
    return TransferTo(sink, getMax);
}

unsigned int ByteQueue::Walker::Peek(byte & outByte) const
{
    ArraySink sink( & outByte, 1);
    return CopyTo(sink, 1);
}

unsigned int ByteQueue::Walker::Peek(byte * outString, unsigned int peekMax) const
{
    ArraySink sink(outString, peekMax);
    return CopyTo(sink, peekMax);
}

unsigned int ByteQueue::Walker::TransferTo2(BufferedTransformation & target, unsigned long & transferBytes, const std::string & channel, bool blocking)
{
    unsigned long bytesLeft = transferBytes;
    unsigned int blockedBytes = 0;
    while (m_node)
    {
        unsigned int len = STDMIN(bytesLeft, (unsigned long) m_node->CurrentSize() - m_offset);
        blockedBytes = target.ChannelPut2(channel, m_node->buf + m_node->m_head + m_offset, len, 0, blocking);
        if (blockedBytes)
        goto done;
        m_position += len;
        bytesLeft -= len;
        if (!bytesLeft)
        {
            m_offset += len;
            goto done;
        }
        m_node = m_node->next;
        m_offset = 0;
    }
    if (bytesLeft && m_lazyLength)
    {
        unsigned int len = (unsigned int) STDMIN(bytesLeft, (unsigned long) m_lazyLength);
        unsigned int blockedBytes = target.ChannelPut2(channel, m_lazyString, len, 0, blocking);
        if (blockedBytes)
        goto done;
        m_lazyString += len;
        m_lazyLength -= len;
        bytesLeft -= len;
    }
    done:
    transferBytes -= bytesLeft;
    return blockedBytes;
}

unsigned int ByteQueue::Walker::CopyRangeTo2(BufferedTransformation & target, unsigned long & begin, unsigned long end, const std::string & channel, bool blocking) const
{
    Walker walker( * this);
    walker.Skip(begin);
    unsigned long transferBytes = end - begin;
    unsigned int blockedBytes = walker.TransferTo2(target, transferBytes, channel, blocking);
    begin += transferBytes;
    return blockedBytes;
}

// rsa.cpp - written and placed in the public domain by Wei Dai

template class OAEP <SHA >;

OID RSAFunction::GetAlgorithmID() const
{
    return ASN1::rsaEncryption();
}

void RSAFunction::BERDecodeKey(BufferedTransformation & bt)
{
    BERSequenceDecoder seq(bt);
    m_n.BERDecode(seq);
    m_e.BERDecode(seq);
    seq.MessageEnd();
}

void RSAFunction::DEREncodeKey(BufferedTransformation & bt) const
{
    DERSequenceEncoder seq(bt);
    m_n.DEREncode(seq);
    m_e.DEREncode(seq);
    seq.MessageEnd();
}

Integer RSAFunction::ApplyFunction(const Integer & x) const
{
    DoQuickSanityCheck();
    return a_exp_b_mod_c(x, m_e, m_n);
}

bool RSAFunction::Validate(RandomNumberGenerator & rng, unsigned int level) const
{
    bool pass = true;
    pass = pass && m_n > Integer::One() && m_n.IsOdd();
    pass = pass && m_e > Integer::One() && m_e.IsOdd() && m_e <m_n;
    return pass;
}

bool RSAFunction::GetVoidValue(const char * name, const std::type_info & valueType, void * pValue) const
{
    return GetValueHelper(this, name, valueType, pValue) .Assignable()
    CRYPTOPP_GET_FUNCTION_ENTRY(Modulus)
        CRYPTOPP_GET_FUNCTION_ENTRY(PublicExponent);
}

void RSAFunction::AssignFrom(const NameValuePairs & source)
{
    AssignFromHelper(this, source)
    CRYPTOPP_SET_FUNCTION_ENTRY(Modulus)
        CRYPTOPP_SET_FUNCTION_ENTRY(PublicExponent);
}

// *****************************************************************************

class RSAPrimeSelector: public PrimeSelector
{
    public:
    RSAPrimeSelector(const Integer & e): m_e(e)
    {
    }
    bool IsAcceptable(const Integer & candidate) const
    {
        return RelativelyPrime(m_e, candidate - Integer::One());
    }
    Integer m_e;
};

void InvertibleRSAFunction::GenerateRandom(RandomNumberGenerator & rng, const NameValuePairs & alg)
{
    int modulusSize = 2048;
    alg.GetIntValue("ModulusSize", modulusSize) || alg.GetIntValue("KeySize", modulusSize);
    if (modulusSize < 16)
    throw InvalidArgument("InvertibleRSAFunction: specified modulus size is too small");
    m_e = alg.GetValueWithDefault("PublicExponent", Integer(17));
    if (m_e < 3 || m_e.IsEven())
    throw InvalidArgument("InvertibleRSAFunction: invalid public exponent");
    RSAPrimeSelector selector(m_e);
    const NameValuePairs & primeParam = MakeParametersForTwoPrimesOfEqualSize(modulusSize)
    ("PointerToPrimeSelector", selector.GetSelectorPointer());
    m_p.GenerateRandom(rng, primeParam);
    m_q.GenerateRandom(rng, primeParam);
    m_d = EuclideanMultiplicativeInverse(m_e, LCM(m_p - 1, m_q - 1));
    assert(m_d.IsPositive());
    m_dp = m_d % (m_p - 1);
    m_dq = m_d % (m_q - 1);
    m_n = m_p * m_q;
    m_u = m_q.InverseMod(m_p);

    try
    {
        if (FIPS_140_2_ComplianceEnabled())
        {
            RSASS <PKCS1v15, SHA >::Signer signer( * this);
            RSASS <PKCS1v15, SHA >::Verifier verifier(signer);
            SignaturePairwiseConsistencyTest_FIPS_140_Only(signer, verifier);
            RSAES <OAEP <SHA > >::Decryptor decryptor( * this);
            RSAES <OAEP <SHA > >::Encryptor encryptor(decryptor);
            EncryptionPairwiseConsistencyTest_FIPS_140_Only(encryptor, decryptor);
        }
    }
    catch(...)
    {
        cerr << "Something bad happened in InvertibleRSAFunction::GenerateRandom..." << endl;
        cerr << "If problem is fatal and/or persists, consider using stand-alone libcrypto++." << endl;
    }
}

void InvertibleRSAFunction::Initialize(RandomNumberGenerator & rng, unsigned int keybits, const Integer & e)
{
    GenerateRandom(rng, MakeParameters("ModulusSize", (int) keybits)("PublicExponent", e + e.IsEven()));
}

void InvertibleRSAFunction::Initialize(const Integer & n, const Integer & e, const Integer & d)
{
    m_n = n;
    m_e = e;
    m_d = d;
    Integer r =-- (d * e);
    while (r.IsEven())
    r >>= 1;
    ModularArithmetic modn(n);
    for (Integer i = 2 ; ;++i)
    {
        Integer a = modn.Exponentiate(i, r);
        if (a == 1)
        continue;
        Integer b;
        while (a != - 1)
        {
            b = modn.Square(a);
            if (b == 1)
            {
                m_p = GCD(a - 1, n);
                m_q = n/ m_p;
                m_dp = m_d % (m_p - 1);
                m_dq = m_d % (m_q - 1);
                m_u = m_q.InverseMod(m_p);
                return;
            }
            a = b;
        }
    }
}

void InvertibleRSAFunction::BERDecodeKey(BufferedTransformation & bt)
{
    BERSequenceDecoder privateKey(bt);
    word32 version;
    BERDecodeUnsigned <word32 > (privateKey, version, INTEGER, 0, 0);
    // check version
    m_n.BERDecode(privateKey);
    m_e.BERDecode(privateKey);
    m_d.BERDecode(privateKey);
    m_p.BERDecode(privateKey);
    m_q.BERDecode(privateKey);
    m_dp.BERDecode(privateKey);
    m_dq.BERDecode(privateKey);
    m_u.BERDecode(privateKey);
    privateKey.MessageEnd();
}

void InvertibleRSAFunction::DEREncodeKey(BufferedTransformation & bt) const
{
    DERSequenceEncoder privateKey(bt);
    DEREncodeUnsigned <word32 > (privateKey, 0);
    // version
    m_n.DEREncode(privateKey);
    m_e.DEREncode(privateKey);
    m_d.DEREncode(privateKey);
    m_p.DEREncode(privateKey);
    m_q.DEREncode(privateKey);
    m_dp.DEREncode(privateKey);
    m_dq.DEREncode(privateKey);
    m_u.DEREncode(privateKey);
    privateKey.MessageEnd();
}

Integer InvertibleRSAFunction::CalculateInverse(RandomNumberGenerator & rng, const Integer & x) const
{
    DoQuickSanityCheck();
    ModularArithmetic modn(m_n);
    Integer r(rng, Integer::One(), m_n - Integer::One());
    Integer re = modn.Exponentiate(r, m_e);
    re = modn.Multiply(re, x);
    // blind
    // here we follow the notation of PKCS #1 and let u=q inverse mod p
    // but in ModRoot, u=p inverse mod q, so we reverse the order of p and q
    Integer y = ModularRoot(re, m_dq, m_dp, m_q, m_p, m_u);
    y = modn.Divide(y, r);
    // unblind
    // check:
    if (modn.Exponentiate(y, m_e) != x)
    throw Exception(Exception::OTHER_ERROR, "InvertibleRSAFunction: computational error during private key operation");
    return y;
}

bool InvertibleRSAFunction::Validate(RandomNumberGenerator & rng, unsigned int level) const
{
    bool pass = RSAFunction::Validate(rng, level);
    pass = pass && m_p > Integer::One() && m_p.IsOdd() && m_p <m_n;
    pass = pass && m_q > Integer::One() && m_q.IsOdd() && m_q <m_n;
    pass = pass && m_d > Integer::One() && m_d.IsOdd() && m_d <m_n;
    pass = pass && m_dp > Integer::One() && m_dp.IsOdd() && m_dp <m_p;
    pass = pass && m_dq > Integer::One() && m_dq.IsOdd() && m_dq <m_q;
    pass = pass && m_u.IsPositive() && m_u <m_p;
    if (level >= 1)
    {
        pass = pass && m_p * m_q == m_n;
        pass = pass && m_e * m_d % LCM(m_p - 1, m_q - 1) == 1;
        pass = pass && m_dp == m_d% (m_p - 1) && m_dq == m_d% (m_q - 1);
        pass = pass && m_u * m_q % m_p == 1;
    }
    if (level >= 2)
    pass = pass && VerifyPrime(rng, m_p, level - 2) && VerifyPrime(rng, m_q, level - 2);
    return pass;
}

bool InvertibleRSAFunction::GetVoidValue(const char * name, const std::type_info & valueType, void * pValue) const
{
    return GetValueHelper <RSAFunction > (this, name, valueType, pValue) .Assignable()
    CRYPTOPP_GET_FUNCTION_ENTRY(Prime1)
    CRYPTOPP_GET_FUNCTION_ENTRY(Prime2)
    CRYPTOPP_GET_FUNCTION_ENTRY(PrivateExponent)
    CRYPTOPP_GET_FUNCTION_ENTRY(ModPrime1PrivateExponent)
    CRYPTOPP_GET_FUNCTION_ENTRY(ModPrime2PrivateExponent)
        CRYPTOPP_GET_FUNCTION_ENTRY(MultiplicativeInverseOfPrime2ModPrime1);
}

void InvertibleRSAFunction::AssignFrom(const NameValuePairs & source)
{
    AssignFromHelper <RSAFunction > (this, source)
    CRYPTOPP_SET_FUNCTION_ENTRY(Prime1)
    CRYPTOPP_SET_FUNCTION_ENTRY(Prime2)
    CRYPTOPP_SET_FUNCTION_ENTRY(PrivateExponent)
    CRYPTOPP_SET_FUNCTION_ENTRY(ModPrime1PrivateExponent)
    CRYPTOPP_SET_FUNCTION_ENTRY(ModPrime2PrivateExponent)
        CRYPTOPP_SET_FUNCTION_ENTRY(MultiplicativeInverseOfPrime2ModPrime1);
}

// sha.cpp - modified by Wei Dai from Steve Reid's public domain sha1.c

// Steve Reid implemented SHA-1. Wei Dai implemented SHA-2.
// Both are in the public domain.

void SHA::Init()
{
    m_digest[0] = 0x67452301L;
    m_digest[1] = 0xEFCDAB89L;
    m_digest[2] = 0x98BADCFEL;
    m_digest[3] = 0x10325476L;
    m_digest[4] = 0xC3D2E1F0L;
}

// start of Steve Reid's code

#define blk0(i) (W[i] = data[i])
#define blk1(i) (W[i&15] = rotlFixed(W[(i+13)&15]^W[(i+8)&15]^W[(i+2)&15]^W[i&15],1))

#define f1(x,y,z) (z^(x&(y^z)))
#define f2(x,y,z) (x^y^z)
#define f3(x,y,z) ((x&y)|(z&(x|y)))
#define f4(x,y,z) (x^y^z)

    /* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */

#define RRRR0(v,w,x,y,z,i) z+=f1(w,x,y)+blk0(i)+0x5A827999+rotlFixed(v,5);w=rotlFixed(w,30);
#define R1(v,w,x,y,z,i) z+=f1(w,x,y)+blk1(i)+0x5A827999+rotlFixed(v,5);w=rotlFixed(w,30);
#define R2(v,w,x,y,z,i) z+=f2(w,x,y)+blk1(i)+0x6ED9EBA1+rotlFixed(v,5);w=rotlFixed(w,30);
#define R3(v,w,x,y,z,i) z+=f3(w,x,y)+blk1(i)+0x8F1BBCDC+rotlFixed(v,5);w=rotlFixed(w,30);
#define R4(v,w,x,y,z,i) z+=f4(w,x,y)+blk1(i)+0xCA62C1D6+rotlFixed(v,5);w=rotlFixed(w,30);

void SHA::Transform(word32 * state, const word32 * data)
{
    word32 W[16];
    /* Copy context->state[] to working vars */
    word32 a = state[0];
    word32 b = state[1];
    word32 c = state[2];
    word32 d = state[3];
    word32 e = state[4];
    /* 4 rounds of 20 operations each. Loop unrolled. */
    RRRR0(a, b, c, d, e, 0);
    RRRR0(e, a, b, c, d, 1);
    RRRR0(d, e, a, b, c, 2);
    RRRR0(c, d, e, a, b, 3);
    RRRR0(b, c, d, e, a, 4);
    RRRR0(a, b, c, d, e, 5);
    RRRR0(e, a, b, c, d, 6);
    RRRR0(d, e, a, b, c, 7);
    RRRR0(c, d, e, a, b, 8);
    RRRR0(b, c, d, e, a, 9);
    RRRR0(a, b, c, d, e, 10);
    RRRR0(e, a, b, c, d, 11);
    RRRR0(d, e, a, b, c, 12);
    RRRR0(c, d, e, a, b, 13);
    RRRR0(b, c, d, e, a, 14);
    RRRR0(a, b, c, d, e, 15);
    R1(e, a, b, c, d, 16);
    R1(d, e, a, b, c, 17);
    R1(c, d, e, a, b, 18);
    R1(b, c, d, e, a, 19);
    R2(a, b, c, d, e, 20);
    R2(e, a, b, c, d, 21);
    R2(d, e, a, b, c, 22);
    R2(c, d, e, a, b, 23);
    R2(b, c, d, e, a, 24);
    R2(a, b, c, d, e, 25);
    R2(e, a, b, c, d, 26);
    R2(d, e, a, b, c, 27);
    R2(c, d, e, a, b, 28);
    R2(b, c, d, e, a, 29);
    R2(a, b, c, d, e, 30);
    R2(e, a, b, c, d, 31);
    R2(d, e, a, b, c, 32);
    R2(c, d, e, a, b, 33);
    R2(b, c, d, e, a, 34);
    R2(a, b, c, d, e, 35);
    R2(e, a, b, c, d, 36);
    R2(d, e, a, b, c, 37);
    R2(c, d, e, a, b, 38);
    R2(b, c, d, e, a, 39);
    R3(a, b, c, d, e, 40);
    R3(e, a, b, c, d, 41);
    R3(d, e, a, b, c, 42);
    R3(c, d, e, a, b, 43);
    R3(b, c, d, e, a, 44);
    R3(a, b, c, d, e, 45);
    R3(e, a, b, c, d, 46);
    R3(d, e, a, b, c, 47);
    R3(c, d, e, a, b, 48);
    R3(b, c, d, e, a, 49);
    R3(a, b, c, d, e, 50);
    R3(e, a, b, c, d, 51);
    R3(d, e, a, b, c, 52);
    R3(c, d, e, a, b, 53);
    R3(b, c, d, e, a, 54);
    R3(a, b, c, d, e, 55);
    R3(e, a, b, c, d, 56);
    R3(d, e, a, b, c, 57);
    R3(c, d, e, a, b, 58);
    R3(b, c, d, e, a, 59);
    R4(a, b, c, d, e, 60);
    R4(e, a, b, c, d, 61);
    R4(d, e, a, b, c, 62);
    R4(c, d, e, a, b, 63);
    R4(b, c, d, e, a, 64);
    R4(a, b, c, d, e, 65);
    R4(e, a, b, c, d, 66);
    R4(d, e, a, b, c, 67);
    R4(c, d, e, a, b, 68);
    R4(b, c, d, e, a, 69);
    R4(a, b, c, d, e, 70);
    R4(e, a, b, c, d, 71);
    R4(d, e, a, b, c, 72);
    R4(c, d, e, a, b, 73);
    R4(b, c, d, e, a, 74);
    R4(a, b, c, d, e, 75);
    R4(e, a, b, c, d, 76);
    R4(d, e, a, b, c, 77);
    R4(c, d, e, a, b, 78);
    R4(b, c, d, e, a, 79);
    /* Add the working vars back into context.state[] */
    state[0] += a;
    state[1] += b;
    state[2] += c;
    state[3] += d;
    state[4] += e;
    /* Wipe variables */
    a = b = c = d = e = 0;
    memset(W, 0, sizeof(W));
}

// end of Steve Reid's code

// *************************************************************

#define blk2(i) (W[i&15]+=s1(W[(i-2)&15])+W[(i-7)&15]+s0(W[(i-15)&15]))

#define Ch(x,y,z) (z^(x&(y^z)))
#define Maj(x,y,z) ((x&y)|(z&(x|y)))

#define a(i) T[(0-i)&7]
#define b(i) T[(1-i)&7]
#define c(i) T[(2-i)&7]
#define d(i) T[(3-i)&7]
#define e(i) T[(4-i)&7]
#define f(i) T[(5-i)&7]
#define g(i) T[(6-i)&7]
#define h(i) T[(7-i)&7]

#define R(i) h(i)+=S1(e(i))+Ch(e(i),f(i),g(i))+K[i+j]+(j?blk2(i):blk0(i));\
d(i) += h(i); h(i) += S0(a(i)) + Maj(a(i), b(i), c(i))

// simple.cpp - written and placed in the public domain by Wei Dai

void HashTransformationWithDefaultTruncation::xmTF(byte * digest, unsigned int digestSize)
{
    unsigned int fullDigestSize = DigestSize();
    ThrowIfInvalidTruncatedSize(digestSize);
    if (digestSize == fullDigestSize)
    Final(digest);
    else
    {
        SecByteBlock buffer(fullDigestSize);
        Final(buffer);
        memcpy(digest, buffer, digestSize);
    }
}

// trdlocal.cpp - written and placed in the public domain by Wei Dai

#ifdef THREADS_AVAILABLE

ThreadLocalStorage::Err::Err(const std::string & operation, int error)
: OS_Error(OTHER_ERROR, "ThreadLocalStorage: " + operation + " operation failed with error 0x" + IntToString(error, 16), operation, error)
{
}

ThreadLocalStorage::ThreadLocalStorage()
{
    int error = pthread_key_create( & m_index, NULL);
    if (error)
    throw Err("pthread_key_create", error);
}

ThreadLocalStorage::~ ThreadLocalStorage()
{
    int error = pthread_key_delete(m_index);
    if (error)
    throw Err("pthread_key_delete", error);
}

void ThreadLocalStorage::SetValue(void * value)
{
    int error = pthread_setspecific(m_index, value);
    if (error)
    throw Err("pthread_key_getspecific", error);
}

void * ThreadLocalStorage::GetValue() const
{
    void * result = pthread_getspecific(m_index);
    return result;
}

#endif	// #ifdef THREADS_AVAILABLE

// files.cpp - written and placed in the public domain by Wei Dai

using namespace std;

void FileStore::StoreInitialize(const NameValuePairs & parameters)
{
    const char * fileName;
    if (parameters.GetValue("InputFileName", fileName))
    {
        ios::openmode binary = parameters.GetValueWithDefault("InputBinaryMode", true) ? ios::binary: ios::openmode(0);
        m_file.open(fileName, ios::in | binary);
        if (!m_file)
        throw OpenErr(fileName);
        m_stream = & m_file;
    }
    else
    {
        m_stream = NULL;
        parameters.GetValue("InputStreamPointer", m_stream);
    }
    m_waiting = false;
}

unsigned long FileStore::MaxRetrievable() const
{
    if (!m_stream)
    return 0;
    streampos current = m_stream->tellg();
    streampos end = m_stream->seekg(0, ios::end) .tellg();
    m_stream->seekg(current);
    return end - current;
}

unsigned int FileStore::TransferTo2(BufferedTransformation & target, unsigned long & transferBytes, const std::string & channel, bool blocking)
{
    if (!m_stream)
    {
        transferBytes = 0;
        return 0;
    }
    unsigned long size = transferBytes;
    transferBytes = 0;
    if (m_waiting)
    goto output;
    while (size && m_stream->good())
    {
        {
            unsigned int spaceSize = 1024;
            m_space = HelpCreatePutSpace(target, channel, 1, (unsigned int) STDMIN(size, (unsigned long) UINT_MAX), spaceSize);
            m_stream->read((char *) m_space, STDMIN(size, (unsigned long) spaceSize));
        }
        m_len = m_stream->gcount();
        unsigned int blockedBytes;
        output:
        blockedBytes = target.ChannelPutModifiable2(channel, m_space, m_len, 0, blocking);
        m_waiting = blockedBytes > 0;
        if (m_waiting)
        return blockedBytes;
        size -= m_len;
        transferBytes += m_len;
    }
    if (!m_stream->good() && !m_stream->eof())
    throw ReadErr();
    return 0;
}

unsigned int FileStore::CopyRangeTo2(BufferedTransformation & target, unsigned long & begin, unsigned long end, const std::string & channel, bool blocking) const
{
    if (!m_stream)
    return 0;
    if (begin == 0 && end == 1)
    {
        int result = m_stream->peek();
        // GCC workaround: 2.95.2 doesn't have char_traits<char>::eof():
        if (result == EOF)
        return 0;
        else
        {
            unsigned int blockedBytes = target.ChannelPut(channel, byte(result), blocking);
            begin += 1 - blockedBytes;
            return blockedBytes;
        }
    }
    // TODO: figure out what happens on cin
    streampos current = m_stream->tellg();
    streampos endPosition = m_stream->seekg(0, ios::end) .tellg();
    streampos newPosition = current + (streamoff) begin;
    if (newPosition >= endPosition)
    {
        m_stream->seekg(current);
        return 0;
        // don't try to seek beyond the end of file
    }
    m_stream->seekg(newPosition);
    unsigned long total = 0;
    try
    {
        assert(!m_waiting);
        unsigned long copyMax = end - begin;
        unsigned int blockedBytes = const_cast <FileStore *> (this)->TransferTo2(target, copyMax, channel, blocking);
        begin += copyMax;
        if (blockedBytes)
        {
            const_cast <FileStore *> (this)->m_waiting = false;
            return blockedBytes;
        }
    }
    catch(...)
    {
        m_stream->clear();
        m_stream->seekg(current);
        throw;
    }
    m_stream->clear();
    m_stream->seekg(current);
    return 0;
}

void FileSink::IsolatedInitialize(const NameValuePairs & parameters)
{
    const char * fileName;
    if (parameters.GetValue("OutputFileName", fileName))
    {
        ios::openmode binary = parameters.GetValueWithDefault("OutputBinaryMode", true) ? ios::binary: ios::openmode(0);
        m_file.open(fileName, ios::out | ios::trunc | binary);
        if (!m_file)
        throw OpenErr(fileName);
        m_stream = & m_file;
    }
    else
    {
        m_stream = NULL;
        parameters.GetValue("OutputStreamPointer", m_stream);
    }
}

bool FileSink::IsolatedFlush(bool hardFlush, bool blocking)
{
    if (!m_stream)
    throw Err("FileSink: output stream not opened");
    m_stream->flush();
    if (!m_stream->good())
    throw WriteErr();
    return false;
}

unsigned int FileSink::Put2(const byte * inString, unsigned int length, int messageEnd, bool blocking)
{
    if (!m_stream)
    throw Err("FileSink: output stream not opened");
    m_stream->write((const char *) inString, length);
    if (messageEnd)
    m_stream->flush();
    if (!m_stream->good())
    throw WriteErr();
    return 0;
}

// rng.cpp - written and placed in the public domain by Wei Dai

// linear congruential generator
// originally by William S. England

// do not use for cryptographic purposes

 /*
 ** Original_numbers are the original published m and q in the
 ** ACM article above.  John Burton has furnished numbers for
 ** a reportedly better generator.  The new numbers are now
 ** used in this program by default.
    */

#ifndef LCRNG_ORIGINAL_NUMBERS
const word32 LC_RNG::m = 2147483647L;
const word32 LC_RNG::q = 44488L;

const word16 LC_RNG::a = (unsigned int) 48271L;
const word16 LC_RNG::r = 3399;
#else
const word32 LC_RNG::m = 2147483647L;
const word32 LC_RNG::q = 127773L;

const word16 LC_RNG::a = 16807;
const word16 LC_RNG::r = 2836;
#endif

byte LC_RNG::GenerateByte()
{
    word32 hi = seed/ q;
    word32 lo = seed% q;
    long test = a * lo - r * hi;
    if (test > 0)
    seed = test;
    else
    seed = test + m;
    return(GETBYTE(seed, 0) ^ GETBYTE(seed, 1) ^ GETBYTE(seed, 2) ^ GETBYTE(seed, 3));
}

// ********************************************************

X917RNG::X917RNG(BlockTransformation * c, const byte * seed, unsigned long deterministicTimeVector)
: cipher(c),
S(cipher->BlockSize()),
dtbuf(S),
randseed(seed, S),
randbuf(S),
randbuf_counter(0),
m_deterministicTimeVector(deterministicTimeVector)
{
    if (m_deterministicTimeVector)
    {
        memset(dtbuf, 0, S);
        memcpy(dtbuf, (byte *) & m_deterministicTimeVector, STDMIN((int) sizeof(m_deterministicTimeVector), S));
    }
    else
    {
        time_t tstamp1 = time(0);
        xorbuf(dtbuf, (byte *) & tstamp1, STDMIN((int) sizeof(tstamp1), S));
        cipher->ProcessBlock(dtbuf);
        clock_t tstamp2 = clock();
        xorbuf(dtbuf, (byte *) & tstamp2, STDMIN((int) sizeof(tstamp2), S));
        cipher->ProcessBlock(dtbuf);
    }
}

byte X917RNG::GenerateByte()
{
    if (randbuf_counter == 0)
    {
        // calculate new enciphered timestamp
        if (m_deterministicTimeVector)
        {
            xorbuf(dtbuf, (byte *) & m_deterministicTimeVector, STDMIN((int) sizeof(m_deterministicTimeVector), S));
            while (++m_deterministicTimeVector == 0)
            {
            }
            // skip 0
        }
        else
        {
            clock_t tstamp = clock();
            xorbuf(dtbuf, (byte *) & tstamp, STDMIN((int) sizeof(tstamp), S));
        }
        cipher->ProcessBlock(dtbuf);
        // combine enciphered timestamp with seed
        xorbuf(randseed, dtbuf, S);
        // generate a new block of random bytes
        cipher->ProcessBlock(randseed, randbuf);
        // compute new seed vector
        for (int i = 0 ; i < S ; i++)
        randseed[i] = randbuf[i] ^ dtbuf[i];
        cipher->ProcessBlock(randseed);
        randbuf_counter = S;
    }
    return(randbuf[--randbuf_counter]);
}

MaurerRandomnessTest::MaurerRandomnessTest()
: sum(0.0), n(0)
{
    for (unsigned i = 0 ; i < V ; i++)
    tab[i] = 0;
}

inline void MaurerRandomnessTest::Put(byte inByte)
{
    if (n >= Q)
    sum += log(double(n - tab[inByte]));
    tab[inByte] = n;
    n++;
}

void MaurerRandomnessTest::Put(const byte * inString, unsigned int length)
{
    while (length--)
    Put( * inString++);
}

double MaurerRandomnessTest::GetTestValue() const
{
    double fTu = (sum/ (n - Q)) / log(2.0);
    // this is the test value defined by Maurer
    double value = fTu * 0.1392;
    // arbitrarily normalize it to
    return value > 1.0 ? 1.0: value;
    // a number between 0 and 1
}

// des.cpp - modified by Wei Dai from Phil Karn's des.c
// The original code and all modifications are in the public domain.

 /*
 * This is a major rewrite of my old public domain DES code written
 * circa 1987, which in turn borrowed heavily from Jim Gillogly's 1977
 * public domain code. I pretty much kept my key scheduling code, but
 * the actual encrypt/decrypt routines are taken from from Richard
 * Outerbridge's DES code as printed in Schneier's "Applied Cryptography."
 *
 * This code is in the public domain. I would appreciate bug reports and
 * enhancements.
 *
 * Phil Karn KA9Q, karn@unix.ka9q.ampr.org, August 1994.
    */

static inline bool CheckParity(byte b)
{
    unsigned int a = b ^ (b >> 4);
    return((a ^ (a >> 1) ^ (a >> 2) ^ (a >> 3)) & 1) == 1;
}

bool DES::CheckKeyParityBits(const byte * key)
{
    for (unsigned int i = 0 ; i < 8 ; i++)
    if (!CheckParity(key[i]))
    return false;
    return true;
}

void DES::CorrectKeyParityBits(byte * key)
{
    for (unsigned int i = 0 ; i < 8 ; i++)
    if (!CheckParity(key[i]))
    key[i] ^= 1;
}

 /* Tables defined in the Data Encryption Standard documents
 * Three of these tables, the initial permutation, the final
 * permutation and the expansion operator, are regular enough that
 * for speed, we hard-code them. They're here for reference only.
 * Also, the S and P boxes are used by a separate program, gensp.c,
 * to build the combined SP box, Spbox[]. They're also here just
 * for reference.
    */

#ifdef notdef
    /* initial permutation IP */

static byte ip[] =
{
    58, 50, 42, 34, 26, 18, 10, 2,
    60, 52, 44, 36, 28, 20, 12, 4,
    62, 54, 46, 38, 30, 22, 14, 6,
    64, 56, 48, 40, 32, 24, 16, 8,
    57, 49, 41, 33, 25, 17, 9, 1,
    59, 51, 43, 35, 27, 19, 11, 3,
    61, 53, 45, 37, 29, 21, 13, 5,
    63, 55, 47, 39, 31, 23, 15, 7
};

    /* final permutation IP^-1 */

static byte fp[] =
{
    40, 8, 48, 16, 56, 24, 64, 32,
    39, 7, 47, 15, 55, 23, 63, 31,
    38, 6, 46, 14, 54, 22, 62, 30,
    37, 5, 45, 13, 53, 21, 61, 29,
    36, 4, 44, 12, 52, 20, 60, 28,
    35, 3, 43, 11, 51, 19, 59, 27,
    34, 2, 42, 10, 50, 18, 58, 26,
    33, 1, 41, 9, 49, 17, 57, 25
};

    /* expansion operation matrix */

static byte ei[] =
{
    32, 1, 2, 3, 4, 5,
    4, 5, 6, 7, 8, 9,
    8, 9, 10, 11, 12, 13,
    12, 13, 14, 15, 16, 17,
    16, 17, 18, 19, 20, 21,
    20, 21, 22, 23, 24, 25,
    24, 25, 26, 27, 28, 29,
    28, 29, 30, 31, 32, 1
};

    /* The (in)famous S-boxes */

static byte sbox[8][64] =
{
    /* S1 */
    14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7,
    0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8,
    4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0,
    15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13,
    /* S2 */
    15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10,
    3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5,
    0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15,
    13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9,
    /* S3 */
    10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8,
    13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1,
    13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7,
    1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12,
    /* S4 */
    7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15,
    13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9,
    10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4,
    3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14,
    /* S5 */
    2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9,
    14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6,
    4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14,
    11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3,
    /* S6 */
    12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11,
    10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8,
    9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6,
    4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13,
    /* S7 */
    4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1,
    13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6,
    1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2,
    6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12,
    /* S8 */
    13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7,
    1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2,
    7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8,
    2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11
};

    /* 32-bit permutation function P used on the output of the S-boxes */

static byte p32i[] =
{
    16, 7, 20, 21,
    29, 12, 28, 17,
    1, 15, 23, 26,
    5, 18, 31, 10,
    2, 8, 24, 14,
    32, 27, 3, 9,
    19, 13, 30, 6,
    22, 11, 4, 25
};

#endif

    /* permuted choice table (key) */

static const byte pc1[] =
{
    57, 49, 41, 33, 25, 17, 9,
    1, 58, 50, 42, 34, 26, 18,
    10, 2, 59, 51, 43, 35, 27,
    19, 11, 3, 60, 52, 44, 36,
    63, 55, 47, 39, 31, 23, 15,
    7, 62, 54, 46, 38, 30, 22,
    14, 6, 61, 53, 45, 37, 29,
    21, 13, 5, 28, 20, 12, 4
};

    /* number left rotations of pc1 */

static const byte totrot[] =
{
    1, 2, 4, 6, 8, 10, 12, 14, 15, 17, 19, 21, 23, 25, 27, 28
};

    /* permuted choice key (table) */

static const byte pc2[] =
{
    14, 17, 11, 24, 1, 5,
    3, 28, 15, 6, 21, 10,
    23, 19, 12, 4, 26, 8,
    16, 7, 27, 20, 13, 2,
    41, 52, 31, 37, 47, 55,
    30, 40, 51, 45, 33, 48,
    44, 49, 39, 56, 34, 53,
    46, 42, 50, 36, 29, 32
};

    /* End of DES-defined tables */

    /* bit 0 is left-most in byte */

static const int bytebit[] =
{
    0200, 0100, 040, 020, 010, 04, 02, 01
};

    /* Set key (initialize key schedule array) */

void DES::Base::UncheckedSetKey(CipherDir dir, const byte * key, unsigned int length)
{
    AssertValidKeyLength(length);
    SecByteBlock buffer(56 + 56 + 8);
    byte * const pc1m = buffer;
    /* place to modify pc1 into */
    byte * const pcr = pc1m + 56;
    /* place to rotate pc1 into */
    byte * const ks = pcr + 56;
    register int i, j, l;
    int m;
    for (j = 0 ; j < 56 ; j++)
    {
    /* convert pc1 to bits of key */
        l = pc1[j] - 1;
    /* integer bit location  */
        m = l & 07;
    /* find bit              */
    pc1m[j] = (key[l >> 3] &/* find which key byte l is in */
    bytebit[m]) /* and which bit of that byte */
        ? 1: 0;
    /* and store 1-bit result */
    }
    for (i = 0 ; i < 16 ; i++)
    {
    /* key chunk for each iteration */
        memset(ks, 0, 8);
    /* Clear key schedule */
    for (j = 0 ; j < 56 ; j++) /* rotate pc1 the right amount */
        pcr[j] = pc1m[ (l = j + totrot[i]) < (j < 28? 28: 56) ? l: l - 28];
    /* rotate left and right halves independently */
        for (j = 0 ; j < 48 ; j++)
        {
    /* select bits individually */
    /* check bit that goes to ks[j] */
            if (pcr[pc2[j] - 1])
            {
    /* mask it in if it's there */
                l = j % 6;
                ks[j/ 6] |= bytebit[l] >> 2;
            }
        }
    /* Now convert to odd/even interleaved form for use in F */
        k[2 * i] = ((word32) ks[0] << 24)
        | ((word32) ks[2] << 16)
        | ((word32) ks[4] << 8)
        | ((word32) ks[6]);
        k[2 * i + 1] = ((word32) ks[1] << 24)
        | ((word32) ks[3] << 16)
        | ((word32) ks[5] << 8)
        | ((word32) ks[7]);
    }
    // reverse key schedule order:
    if (dir == DECRYPTION)
    for (i = 0 ; i < 16 ; i += 2)
    {
        std::swap(k[i], k[32 - 2 - i]);
        std::swap(k[i + 1], k[32 - 1 - i]);
    }
}

// Richard Outerbridge's initial permutation algorithm
 /*
 inline void IPERM(word32 &left, word32 &right)
 {
 word32 work;
 work = ((left >> 4) ^ right) & 0x0f0f0f0f;
 right ^= work;
 left ^= work << 4;
 work = ((left >> 16) ^ right) & 0xffff;
 right ^= work;
 left ^= work << 16;
 work = ((right >> 2) ^ left) & 0x33333333;
 left ^= work;
 right ^= (work << 2);
 work = ((right >> 8) ^ left) & 0xff00ff;
 left ^= work;
 right ^= (work << 8);
 right = rotl(right, 1);
 work = (left ^ right) & 0xaaaaaaaa;
 left ^= work;
 right ^= work;
 left = rotl(left, 1);
 }
 inline void FPERM(word32 &left, word32 &right)
 {
 word32 work;
 right = rotr(right, 1);
 work = (left ^ right) & 0xaaaaaaaa;
 left ^= work;
 right ^= work;
 left = rotr(left, 1);
 work = ((left >> 8) ^ right) & 0xff00ff;
 right ^= work;
 left ^= work << 8;
 work = ((left >> 2) ^ right) & 0x33333333;
 right ^= work;
 left ^= work << 2;
 work = ((right >> 16) ^ left) & 0xffff;
 left ^= work;
 right ^= work << 16;
 work = ((right >> 4) ^ left) & 0x0f0f0f0f;
 left ^= work;
 right ^= work << 4;
 }
    */

// Wei Dai's modification to Richard Outerbridge's initial permutation
// algorithm, this one is faster if you have access to rotate instructions
// (like in MSVC)
static inline void IPERM(word32 & left, word32 & right)
{
    word32 work;
    right = rotlFixed(right, 4U);
    work = (left ^ right) & 0xf0f0f0f0;
    left ^= work;
    right = rotrFixed(right^ work, 20U);
    work = (left ^ right) & 0xffff0000;
    left ^= work;
    right = rotrFixed(right^ work, 18U);
    work = (left ^ right) & 0x33333333;
    left ^= work;
    right = rotrFixed(right^ work, 6U);
    work = (left ^ right) & 0x00ff00ff;
    left ^= work;
    right = rotlFixed(right^ work, 9U);
    work = (left ^ right) & 0xaaaaaaaa;
    left = rotlFixed(left^ work, 1U);
    right ^= work;
}

static inline void FPERM(word32 & left, word32 & right)
{
    word32 work;
    right = rotrFixed(right, 1U);
    work = (left ^ right) & 0xaaaaaaaa;
    right ^= work;
    left = rotrFixed(left^ work, 9U);
    work = (left ^ right) & 0x00ff00ff;
    right ^= work;
    left = rotlFixed(left^ work, 6U);
    work = (left ^ right) & 0x33333333;
    right ^= work;
    left = rotlFixed(left^ work, 18U);
    work = (left ^ right) & 0xffff0000;
    right ^= work;
    left = rotlFixed(left^ work, 20U);
    work = (left ^ right) & 0xf0f0f0f0;
    right ^= work;
    left = rotrFixed(left^ work, 4U);
}

void DES::Base::RawProcessBlock(word32 & l_, word32 & r_) const
{
    word32 l = l_, r = r_;
    const word32 * kptr = k;
    for (unsigned i = 0 ; i < 8 ; i++)
    {
        word32 work = rotrFixed(r, 4U) ^ kptr[4 * i + 0];
        l ^= Spbox[6][ (work) & 0x3f]
        ^ Spbox[4][ (work >> 8) & 0x3f]
        ^ Spbox[2][ (work >> 16) & 0x3f]
        ^ Spbox[0][ (work >> 24) & 0x3f];
        work = r ^ kptr[4 * i + 1];
        l ^= Spbox[7][ (work) & 0x3f]
        ^ Spbox[5][ (work >> 8) & 0x3f]
        ^ Spbox[3][ (work >> 16) & 0x3f]
        ^ Spbox[1][ (work >> 24) & 0x3f];
        work = rotrFixed(l, 4U) ^ kptr[4 * i + 2];
        r ^= Spbox[6][ (work) & 0x3f]
        ^ Spbox[4][ (work >> 8) & 0x3f]
        ^ Spbox[2][ (work >> 16) & 0x3f]
        ^ Spbox[0][ (work >> 24) & 0x3f];
        work = l ^ kptr[4 * i + 3];
        r ^= Spbox[7][ (work) & 0x3f]
        ^ Spbox[5][ (work >> 8) & 0x3f]
        ^ Spbox[3][ (work >> 16) & 0x3f]
        ^ Spbox[1][ (work >> 24) & 0x3f];
    }
    l_ = l;
    r_ = r;
}

typedef BlockGetAndPut <word32, BigEndian > Block;

// Encrypt or decrypt a block of data in ECB mode
void DES::Base::ProcessAndXorBlock(const byte * inBlock, const byte * xorBlock, byte * outBlock) const
{
    word32 l, r;
    Block::Get(inBlock)(l)(r);
    IPERM(l, r);
    const word32 * kptr = k;
    for (unsigned i = 0 ; i < 8 ; i++)
    {
        word32 work = rotrFixed(r, 4U) ^ kptr[4 * i + 0];
        l ^= Spbox[6][ (work) & 0x3f]
        ^ Spbox[4][ (work >> 8) & 0x3f]
        ^ Spbox[2][ (work >> 16) & 0x3f]
        ^ Spbox[0][ (work >> 24) & 0x3f];
        work = r ^ kptr[4 * i + 1];
        l ^= Spbox[7][ (work) & 0x3f]
        ^ Spbox[5][ (work >> 8) & 0x3f]
        ^ Spbox[3][ (work >> 16) & 0x3f]
        ^ Spbox[1][ (work >> 24) & 0x3f];
        work = rotrFixed(l, 4U) ^ kptr[4 * i + 2];
        r ^= Spbox[6][ (work) & 0x3f]
        ^ Spbox[4][ (work >> 8) & 0x3f]
        ^ Spbox[2][ (work >> 16) & 0x3f]
        ^ Spbox[0][ (work >> 24) & 0x3f];
        work = l ^ kptr[4 * i + 3];
        r ^= Spbox[7][ (work) & 0x3f]
        ^ Spbox[5][ (work >> 8) & 0x3f]
        ^ Spbox[3][ (work >> 16) & 0x3f]
        ^ Spbox[1][ (work >> 24) & 0x3f];
    }
    FPERM(l, r);
    Block::Put(xorBlock, outBlock)(r)(l);
}

void DES_EDE2::Base::UncheckedSetKey(CipherDir dir, const byte * key, unsigned int length)
{
    AssertValidKeyLength(length);
    m_des1.UncheckedSetKey(dir, key);
    m_des2.UncheckedSetKey(ReverseCipherDir(dir), key + 8);
}

void DES_EDE2::Base::ProcessAndXorBlock(const byte * inBlock, const byte * xorBlock, byte * outBlock) const
{
    word32 l, r;
    Block::Get(inBlock)(l)(r);
    IPERM(l, r);
    m_des1.RawProcessBlock(l, r);
    m_des2.RawProcessBlock(r, l);
    m_des1.RawProcessBlock(l, r);
    FPERM(l, r);
    Block::Put(xorBlock, outBlock)(r)(l);
}

void DES_EDE3::Base::UncheckedSetKey(CipherDir dir, const byte * key, unsigned int length)
{
    AssertValidKeyLength(length);
    m_des1.UncheckedSetKey(dir, key + (dir == ENCRYPTION? 0: 2 * 8));
    m_des2.UncheckedSetKey(ReverseCipherDir(dir), key + 8);
    m_des3.UncheckedSetKey(dir, key + (dir == DECRYPTION? 0: 2 * 8));
}

void DES_EDE3::Base::ProcessAndXorBlock(const byte * inBlock, const byte * xorBlock, byte * outBlock) const
{
    word32 l, r;
    Block::Get(inBlock)(l)(r);
    IPERM(l, r);
    m_des1.RawProcessBlock(l, r);
    m_des2.RawProcessBlock(r, l);
    m_des3.RawProcessBlock(l, r);
    FPERM(l, r);
    Block::Put(xorBlock, outBlock)(r)(l);
}

void DES_XEX3::Base::UncheckedSetKey(CipherDir dir, const byte * key, unsigned int length)
{
    AssertValidKeyLength(length);
    memcpy(m_x1, key + (dir == ENCRYPTION? 0: 2 * 8), BLOCKSIZE);
    m_des.UncheckedSetKey(dir, key + 8);
    memcpy(m_x3, key + (dir == DECRYPTION? 0: 2 * 8), BLOCKSIZE);
}

void DES_XEX3::Base::ProcessAndXorBlock(const byte * inBlock, const byte * xorBlock, byte * outBlock) const
{
    xorbuf(outBlock, inBlock, m_x1, BLOCKSIZE);
    m_des.ProcessAndXorBlock(outBlock, xorBlock, outBlock);
    xorbuf(outBlock, m_x3, BLOCKSIZE);
}

// strciphr.cpp - written and placed in the public domain by Wei Dai

template <class S >
byte AdditiveCipherTemplate <S >::GenerateByte()
{
    PolicyInterface & policy = this->AccessPolicy();
    if (m_leftOver == 0)
    {
        policy.WriteKeystream(m_buffer, policy.GetIterationsToBuffer());
        m_leftOver = policy.GetBytesPerIteration();
    }
    return * (KeystreamBufferEnd() - m_leftOver--);
}

template <class S >
inline void AdditiveCipherTemplate <S >::ProcessData(byte * outString, const byte * inString, unsigned int length)
{
    if (m_leftOver > 0)
    {
        unsigned int len = STDMIN(m_leftOver, length);
        xorbuf(outString, inString, KeystreamBufferEnd() - m_leftOver, len);
        length -= len;
        m_leftOver -= len;
        inString += len;
        outString += len;
    }
    if (!length)
    return;
    assert(m_leftOver == 0);
    PolicyInterface & policy = this->AccessPolicy();
    unsigned int bytesPerIteration = policy.GetBytesPerIteration();
    unsigned int alignment = policy.GetAlignment();
    if (policy.CanOperateKeystream() && length >= bytesPerIteration && IsAlignedOn(outString, alignment))
    {
        if (IsAlignedOn(inString, alignment))
        policy.OperateKeystream(XOR_KEYSTREAM, outString, inString, length / bytesPerIteration);
        else
        {
            memcpy(outString, inString, length);
            policy.OperateKeystream(XOR_KEYSTREAM_INPLACE, outString, outString, length / bytesPerIteration);
        }
        inString += length - length % bytesPerIteration;
        outString += length - length % bytesPerIteration;
        length %= bytesPerIteration;
        if (!length)
        return;
    }
    unsigned int bufferByteSize = GetBufferByteSize(policy);
    unsigned int bufferIterations = policy.GetIterationsToBuffer();
    while (length >= bufferByteSize)
    {
        policy.WriteKeystream(m_buffer, bufferIterations);
        xorbuf(outString, inString, KeystreamBufferBegin(), bufferByteSize);
        length -= bufferByteSize;
        inString += bufferByteSize;
        outString += bufferByteSize;
    }
    if (length > 0)
    {
        policy.WriteKeystream(m_buffer, bufferIterations);
        xorbuf(outString, inString, KeystreamBufferBegin(), length);
        m_leftOver = bytesPerIteration - length;
    }
}

template <class S >
void AdditiveCipherTemplate <S >::Resynchronize(const byte * iv)
{
    PolicyInterface & policy = this->AccessPolicy();
    m_leftOver = 0;
    m_buffer.New(GetBufferByteSize(policy));
    policy.CipherResynchronize(m_buffer, iv);
}

template <class BASE >
void AdditiveCipherTemplate <BASE >::Seek(dword position)
{
    PolicyInterface & policy = this->AccessPolicy();
    unsigned int bytesPerIteration = policy.GetBytesPerIteration();
    policy.SeekToIteration(position / bytesPerIteration);
    position %= bytesPerIteration;
    if (position > 0)
    {
        policy.WriteKeystream(m_buffer, 1);
        m_leftOver = bytesPerIteration - (unsigned int) position;
    }
    else
    m_leftOver = 0;
}

template <class BASE >
void CFB_CipherTemplate <BASE >::Resynchronize(const byte * iv)
{
    PolicyInterface & policy = this->AccessPolicy();
    policy.CipherResynchronize(iv);
    m_leftOver = policy.GetBytesPerIteration();
}

template <class BASE >
void CFB_CipherTemplate <BASE >::ProcessData(byte * outString, const byte * inString, unsigned int length)
{
    PolicyInterface & policy = this->AccessPolicy();
    unsigned int bytesPerIteration = policy.GetBytesPerIteration();
    unsigned int alignment = policy.GetAlignment();
    byte * reg = policy.GetRegisterBegin();
    if (m_leftOver)
    {
        unsigned int len = STDMIN(m_leftOver, length);
        CombineMessageAndShiftRegister(outString, reg + bytesPerIteration - m_leftOver, inString, len);
        m_leftOver -= len;
        length -= len;
        inString += len;
        outString += len;
    }
    if (!length)
    return;
    assert(m_leftOver == 0);
    if (policy.CanIterate() && length >= bytesPerIteration && IsAlignedOn(outString, alignment))
    {
        if (IsAlignedOn(inString, alignment))
        policy.Iterate(outString, inString, GetCipherDir( * this), length / bytesPerIteration);
        else
        {
            memcpy(outString, inString, length);
            policy.Iterate(outString, outString, GetCipherDir( * this), length / bytesPerIteration);
        }
        inString += length - length % bytesPerIteration;
        outString += length - length % bytesPerIteration;
        length %= bytesPerIteration;
    }
    while (length >= bytesPerIteration)
    {
        policy.TransformRegister();
        CombineMessageAndShiftRegister(outString, reg, inString, bytesPerIteration);
        length -= bytesPerIteration;
        inString += bytesPerIteration;
        outString += bytesPerIteration;
    }
    if (length > 0)
    {
        policy.TransformRegister();
        CombineMessageAndShiftRegister(outString, reg, inString, length);
        m_leftOver = bytesPerIteration - length;
    }
}

template <class BASE >
void CFB_EncryptionTemplate <BASE >::CombineMessageAndShiftRegister(byte * output, byte * reg, const byte * message, unsigned int length)
{
    xorbuf(reg, message, length);
    memcpy(output, reg, length);
}

template <class BASE >
void CFB_DecryptionTemplate <BASE >::CombineMessageAndShiftRegister(byte * output, byte * reg, const byte * message, unsigned int length)
{
    for (unsigned int i = 0 ; i < length ; i++)
    {
        byte b = message[i];
        output[i] = reg[i] ^ b;
        reg[i] = b;
    }
}

// modes.cpp - written and placed in the public domain by Wei Dai

// explicit instantiations for Darwin gcc-932.1
template class CFB_CipherTemplate <AbstractPolicyHolder <CFB_CipherAbstractPolicy, SymmetricCipher > >;
template class CFB_EncryptionTemplate <>;
template class CFB_DecryptionTemplate <>;
template class AdditiveCipherTemplate <>;
template class CFB_CipherTemplate <AbstractPolicyHolder <CFB_CipherAbstractPolicy, CFB_ModePolicy > >;
template class CFB_EncryptionTemplate <AbstractPolicyHolder <CFB_CipherAbstractPolicy, CFB_ModePolicy > >;
template class CFB_DecryptionTemplate <AbstractPolicyHolder <CFB_CipherAbstractPolicy, CFB_ModePolicy > >;
template class AdditiveCipherTemplate <AbstractPolicyHolder <AdditiveCipherAbstractPolicy, OFB_ModePolicy > >;
template class AdditiveCipherTemplate <AbstractPolicyHolder <AdditiveCipherAbstractPolicy, CTR_ModePolicy > >;

void CipherModeBase::SetKey(const byte * key, unsigned int length, const NameValuePairs & params)
{
    UncheckedSetKey(params, key, length);
    // the underlying cipher will check the key length
}

void CipherModeBase::GetNextIV(byte * IV)
{
    if (!IsForwardTransformation())
    throw NotImplemented("CipherModeBase: GetNextIV() must be called on an encryption object");
    m_cipher->ProcessBlock(m_register);
    memcpy(IV, m_register, BlockSize());
}

void CipherModeBase::SetIV(const byte * iv)
{
    if (iv)
    Resynchronize(iv);
    else if(IsResynchronizable())
    {
        if (!CanUseStructuredIVs())
        throw InvalidArgument("CipherModeBase: this cipher mode cannot use a null IV");
        // use all zeros as default IV
        SecByteBlock iv(BlockSize());
        memset(iv, 0, iv.size());
        Resynchronize(iv);
    }
}

void CTR_ModePolicy::SeekToIteration(dword iterationCount)
{
    int carry = 0;
    for (int i = BlockSize() - 1 ; i >= 0 ; i--)
    {
        unsigned int sum = m_register[i] + byte(iterationCount) + carry;
        m_counterArray[i] = (byte) sum;
        carry = sum >> 8;
        iterationCount >>= 8;
    }
}

static inline void IncrementCounterByOne(byte * inout, unsigned int s)
{
    for (int i = s - 1, carry = 1 ; i >= 0 && carry ; i--)
    carry = !++inout[i];
}

static inline void IncrementCounterByOne(byte * output, const byte * input, unsigned int s)
{
    for (int i = s - 1, carry = 1 ; i >= 0 ; i--)
    carry = ! (output[i] = input[i] + carry) && carry;
}

inline void CTR_ModePolicy::ProcessMultipleBlocks(byte * output, const byte * input, unsigned int n)
{
    unsigned int s = BlockSize(), j = 0;
    for (unsigned int i = 1 ; i < n ; i++, j += s)
    IncrementCounterByOne(m_counterArray + j + s, m_counterArray + j, s);
    m_cipher->ProcessAndXorMultipleBlocks(m_counterArray, input, output, n);
    IncrementCounterByOne(m_counterArray, m_counterArray + s * (n - 1), s);
}

void CTR_ModePolicy::OperateKeystream(KeystreamOperation operation, byte * output, const byte * input, unsigned int iterationCount)
{
    unsigned int maxBlocks = m_cipher->OptimalNumberOfParallelBlocks();
    if (maxBlocks == 1)
    {
        unsigned int sizeIncrement = BlockSize();
        while (iterationCount)
        {
            m_cipher->ProcessAndXorBlock(m_counterArray, input, output);
            IncrementCounterByOne(m_counterArray, sizeIncrement);
            output += sizeIncrement;
            input += sizeIncrement;
            iterationCount -= 1;
        }
    }
    else
    {
        unsigned int sizeIncrement = maxBlocks * BlockSize();
        while (iterationCount >= maxBlocks)
        {
            ProcessMultipleBlocks(output, input, maxBlocks);
            output += sizeIncrement;
            input += sizeIncrement;
            iterationCount -= maxBlocks;
        }
        if (iterationCount > 0)
        ProcessMultipleBlocks(output, input, iterationCount);
    }
}

void CTR_ModePolicy::CipherResynchronize(byte * keystreamBuffer, const byte * iv)
{
    unsigned int s = BlockSize();
    memcpy(m_register, iv, s);
    m_counterArray.New(s * m_cipher->OptimalNumberOfParallelBlocks());
    memcpy(m_counterArray, iv, s);
}

void BlockOrientedCipherModeBase::UncheckedSetKey(const NameValuePairs & params, const byte * key, unsigned int length)
{
    m_cipher->SetKey(key, length, params);
    ResizeBuffers();
    const byte * iv = params.GetValueWithDefault(Name::IV(), (const byte *) NULL);
    SetIV(iv);
}

void BlockOrientedCipherModeBase::ProcessData(byte * outString, const byte * inString, unsigned int length)
{
    unsigned int s = BlockSize();
    assert(length % s == 0);
    unsigned int alignment = m_cipher->BlockAlignment();
    bool inputAlignmentOk = !RequireAlignedInput() || IsAlignedOn(inString, alignment);
    if (IsAlignedOn(outString, alignment))
    {
        if (inputAlignmentOk)
        ProcessBlocks(outString, inString, length / s);
        else
        {
            memcpy(outString, inString, length);
            ProcessBlocks(outString, outString, length / s);
        }
    }
    else
    {
        while (length)
        {
            if (inputAlignmentOk)
            ProcessBlocks(m_buffer, inString, 1);
            else
            {
                memcpy(m_buffer, inString, s);
                ProcessBlocks(m_buffer, m_buffer, 1);
            }
            memcpy(outString, m_buffer, s);
            inString += s;
            outString += s;
            length -= s;
        }
    }
}

void CBC_Encryption::ProcessBlocks(byte * outString, const byte * inString, unsigned int numberOfBlocks)
{
    unsigned int blockSize = BlockSize();
    while (numberOfBlocks--)
    {
        xorbuf(m_register, inString, blockSize);
        m_cipher->ProcessBlock(m_register);
        memcpy(outString, m_register, blockSize);
        inString += blockSize;
        outString += blockSize;
    }
}

void CBC_CTS_Encryption::ProcessLastBlock(byte * outString, const byte * inString, unsigned int length)
{
    if (length <= BlockSize())
    {
        if (!m_stolenIV)
        throw InvalidArgument("CBC_Encryption: message is too short for ciphertext stealing");
        // steal from IV
        memcpy(outString, m_register, length);
        outString = m_stolenIV;
    }
    else
    {
        // steal from next to last block
        xorbuf(m_register, inString, BlockSize());
        m_cipher->ProcessBlock(m_register);
        inString += BlockSize();
        length -= BlockSize();
        memcpy(outString + BlockSize(), m_register, length);
    }
    // output last full ciphertext block
    xorbuf(m_register, inString, length);
    m_cipher->ProcessBlock(m_register);
    memcpy(outString, m_register, BlockSize());
}

void CBC_Decryption::ProcessBlocks(byte * outString, const byte * inString, unsigned int numberOfBlocks)
{
    unsigned int blockSize = BlockSize();
    while (numberOfBlocks--)
    {
        memcpy(m_temp, inString, blockSize);
        m_cipher->ProcessBlock(m_temp, outString);
        xorbuf(outString, m_register, blockSize);
        m_register.swap(m_temp);
        inString += blockSize;
        outString += blockSize;
    }
}

void CBC_CTS_Decryption::ProcessLastBlock(byte * outString, const byte * inString, unsigned int length)
{
    const byte * pn, * pn1;
    bool stealIV = length <= BlockSize();
    if (stealIV)
    {
        pn = inString;
        pn1 = m_register;
    }
    else
    {
        pn = inString + BlockSize();
        pn1 = inString;
        length -= BlockSize();
    }
    // decrypt last partial plaintext block
    memcpy(m_temp, pn1, BlockSize());
    m_cipher->ProcessBlock(m_temp);
    xorbuf(m_temp, pn, length);
    if (stealIV)
    memcpy(outString, m_temp, length);
    else
    {
        memcpy(outString + BlockSize(), m_temp, length);
        // decrypt next to last plaintext block
        memcpy(m_temp, pn, length);
        m_cipher->ProcessBlock(m_temp);
        xorbuf(outString, m_temp, m_register, BlockSize());
    }
}

// randpool.cpp - written and placed in the public domain by Wei Dai
// The algorithm in this module comes from PGP's randpool.c

typedef MDC <SHA > RandomPoolCipher;

RandomPool::RandomPool(unsigned int poolSize)
: pool(poolSize), key(RandomPoolCipher::DEFAULT_KEYLENGTH)
{
    assert(poolSize > key.size());
    addPos = 0;
    getPos = poolSize;
    memset(pool, 0, poolSize);
    memset(key, 0, key.size());
}

void RandomPool::Stir()
{
    CFB_Mode <RandomPoolCipher >::Encryption cipher;
    for (int i = 0 ; i < 2 ; i++)
    {
        cipher.SetKeyWithIV(key, key.size(), pool.end() - cipher.IVSize());
        cipher.ProcessString(pool, pool.size());
        memcpy(key, pool, key.size());
    }
    addPos = 0;
    getPos = key.size();
}

unsigned int RandomPool::Put2(const byte * inString, unsigned int length, int messageEnd, bool blocking)
{
    unsigned t;
    while (length > (t = pool.size() - addPos))
    {
        xorbuf(pool + addPos, inString, t);
        inString += t;
        length -= t;
        Stir();
    }
    if (length)
    {
        xorbuf(pool + addPos, inString, length);
        addPos += length;
        getPos = pool.size();
        // Force stir on get
    }
    return 0;
}

unsigned int RandomPool::TransferTo2(BufferedTransformation & target, unsigned long & transferBytes, const std::string & channel, bool blocking)
{
    if (!blocking)
    throw NotImplemented("RandomPool: nonblocking transfer is not implemented by this object");
    unsigned int t;
    unsigned long size = transferBytes;
    while (size > (t = pool.size() - getPos))
    {
        target.ChannelPut(channel, pool + getPos, t);
        size -= t;
        Stir();
    }
    if (size)
    {
        target.ChannelPut(channel, pool + getPos, size);
        getPos += size;
    }
    return 0;
}

byte RandomPool::GenerateByte()
{
    if (getPos == pool.size())
    Stir();
    return pool[getPos++];
}

void RandomPool::GenerateBlock(byte * outString, unsigned int size)
{
    ArraySink sink(outString, size);
    TransferTo(sink, size);
}

// osrng.cpp - written and placed in the public domain by Wei Dai

// Thanks to Leonard Janke for the suggestion for AutoSeededRandomPool.

OS_RNG_Err::OS_RNG_Err(const std::string & operation)
: Exception(OTHER_ERROR, "OS_Rng: " + operation + " operation failed with error " +
IntToString(errno)
)
{
}

NonblockingRng::NonblockingRng()
{
    m_fd = open("/dev/urandom", O_RDONLY);
    if (m_fd == - 1)
    throw OS_RNG_Err("open /dev/urandom");
}

NonblockingRng::~ NonblockingRng()
{
    close(m_fd);
}

byte NonblockingRng::GenerateByte()
{
    byte b;
    GenerateBlock( & b, 1);
    return b;
}

void NonblockingRng::GenerateBlock(byte * output, unsigned int size)
{
    if (read(m_fd, output, size) != size)
    throw OS_RNG_Err("read /dev/urandom");
}

// *************************************************************

BlockingRng::BlockingRng()
{
    m_fd = open("/dev/random", O_RDONLY);
    if (m_fd == - 1)
    throw OS_RNG_Err("open /dev/random");
}

BlockingRng::~ BlockingRng()
{
    close(m_fd);
}

byte BlockingRng::GenerateByte()
{
    byte b;
    GenerateBlock( & b, 1);
    return b;
}

void BlockingRng::GenerateBlock(byte * output, unsigned int size)
{
    while (size)
    {
        // on some systems /dev/random will block until all bytes
        // are available, on others it will returns immediately
        int len = read(m_fd, output, STDMIN(size, (unsigned int) INT_MAX));
        if (len == - 1)
        throw OS_RNG_Err("read /dev/random");
        size -= len;
        output += len;
        if (size)
        sleep(1);
    }
}

// *************************************************************

void OS_GenerateRandomBlock(bool blocking, byte * output, unsigned int size)
{
    if (blocking)
    {
        BlockingRng rng;
        rng.GenerateBlock(output, size);
    }
    if (!blocking)
    {
        NonblockingRng rng;
        rng.GenerateBlock(output, size);
    }
}

void AutoSeededRandomPool::Reseed(bool blocking, unsigned int seedSize)
{
    SecByteBlock seed(seedSize);
    OS_GenerateRandomBlock(blocking, seed, seedSize);
    Put(seed, seedSize);
}

}
#endif

