Path: blob/a-new-beginning/SharedDependencies/Sources/cryptopp/ecp.cpp
2 views
// ecp.cpp - originally written and placed in the public domain by Wei Dai12#include "pch.h"34#ifndef CRYPTOPP_IMPORTS56#include "ecp.h"7#include "asn.h"8#include "integer.h"9#include "nbtheory.h"10#include "modarith.h"11#include "filters.h"12#include "algebra.cpp"1314ANONYMOUS_NAMESPACE_BEGIN1516using CryptoPP::ECP;17using CryptoPP::Integer;18using CryptoPP::ModularArithmetic;1920#if defined(HAVE_GCC_INIT_PRIORITY)21#define INIT_ATTRIBUTE __attribute__ ((init_priority (CRYPTOPP_INIT_PRIORITY + 50)))22const ECP::Point g_identity INIT_ATTRIBUTE = ECP::Point();23#elif defined(HAVE_MSC_INIT_PRIORITY)24#pragma warning(disable: 4075)25#pragma init_seg(".CRT$XCU")26const ECP::Point g_identity;27#pragma warning(default: 4075)28#elif defined(HAVE_XLC_INIT_PRIORITY)29#pragma priority(290)30const ECP::Point g_identity;31#endif3233inline ECP::Point ToMontgomery(const ModularArithmetic &mr, const ECP::Point &P)34{35return P.identity ? P : ECP::Point(mr.ConvertIn(P.x), mr.ConvertIn(P.y));36}3738inline ECP::Point FromMontgomery(const ModularArithmetic &mr, const ECP::Point &P)39{40return P.identity ? P : ECP::Point(mr.ConvertOut(P.x), mr.ConvertOut(P.y));41}4243inline Integer IdentityToInteger(bool val)44{45return val ? Integer::One() : Integer::Zero();46}4748struct ProjectivePoint49{50ProjectivePoint() {}51ProjectivePoint(const Integer &x, const Integer &y, const Integer &z)52: x(x), y(y), z(z) {}5354Integer x, y, z;55};5657ANONYMOUS_NAMESPACE_END5859NAMESPACE_BEGIN(CryptoPP)6061ECP::ECP(const ECP &ecp, bool convertToMontgomeryRepresentation)62{63if (convertToMontgomeryRepresentation && !ecp.GetField().IsMontgomeryRepresentation())64{65m_fieldPtr.reset(new MontgomeryRepresentation(ecp.GetField().GetModulus()));66m_a = GetField().ConvertIn(ecp.m_a);67m_b = GetField().ConvertIn(ecp.m_b);68}69else70operator=(ecp);71}7273ECP::ECP(BufferedTransformation &bt)74: m_fieldPtr(new Field(bt))75{76BERSequenceDecoder seq(bt);77GetField().BERDecodeElement(seq, m_a);78GetField().BERDecodeElement(seq, m_b);79// skip optional seed80if (!seq.EndReached())81{82SecByteBlock seed;83unsigned int unused;84BERDecodeBitString(seq, seed, unused);85}86seq.MessageEnd();87}8889void ECP::DEREncode(BufferedTransformation &bt) const90{91GetField().DEREncode(bt);92DERSequenceEncoder seq(bt);93GetField().DEREncodeElement(seq, m_a);94GetField().DEREncodeElement(seq, m_b);95seq.MessageEnd();96}9798bool ECP::DecodePoint(ECP::Point &P, const byte *encodedPoint, size_t encodedPointLen) const99{100StringStore store(encodedPoint, encodedPointLen);101return DecodePoint(P, store, encodedPointLen);102}103104bool ECP::DecodePoint(ECP::Point &P, BufferedTransformation &bt, size_t encodedPointLen) const105{106byte type;107if (encodedPointLen < 1 || !bt.Get(type))108return false;109110switch (type)111{112case 0:113P.identity = true;114return true;115case 2:116case 3:117{118if (encodedPointLen != EncodedPointSize(true))119return false;120121// Check for p is prime due to GH #1249122const Integer p = FieldSize();123CRYPTOPP_ASSERT(IsPrime(p));124if (!IsPrime(p))125return false;126127P.identity = false;128P.x.Decode(bt, GetField().MaxElementByteLength());129P.y = ((P.x*P.x+m_a)*P.x+m_b) % p;130131if (Jacobi(P.y, p) !=1)132return false;133134// Callers must ensure p is prime, GH #1249135P.y = ModularSquareRoot(P.y, p);136137if ((type & 1) != P.y.GetBit(0))138P.y = p-P.y;139140return true;141}142case 4:143{144if (encodedPointLen != EncodedPointSize(false))145return false;146147unsigned int len = GetField().MaxElementByteLength();148P.identity = false;149P.x.Decode(bt, len);150P.y.Decode(bt, len);151return true;152}153default:154return false;155}156}157158void ECP::EncodePoint(BufferedTransformation &bt, const Point &P, bool compressed) const159{160if (P.identity)161NullStore().TransferTo(bt, EncodedPointSize(compressed));162else if (compressed)163{164bt.Put((byte)(2U + P.y.GetBit(0)));165P.x.Encode(bt, GetField().MaxElementByteLength());166}167else168{169unsigned int len = GetField().MaxElementByteLength();170bt.Put(4U); // uncompressed171P.x.Encode(bt, len);172P.y.Encode(bt, len);173}174}175176void ECP::EncodePoint(byte *encodedPoint, const Point &P, bool compressed) const177{178ArraySink sink(encodedPoint, EncodedPointSize(compressed));179EncodePoint(sink, P, compressed);180CRYPTOPP_ASSERT(sink.TotalPutLength() == EncodedPointSize(compressed));181}182183ECP::Point ECP::BERDecodePoint(BufferedTransformation &bt) const184{185SecByteBlock str;186BERDecodeOctetString(bt, str);187Point P;188if (!DecodePoint(P, str, str.size()))189BERDecodeError();190return P;191}192193void ECP::DEREncodePoint(BufferedTransformation &bt, const Point &P, bool compressed) const194{195SecByteBlock str(EncodedPointSize(compressed));196EncodePoint(str, P, compressed);197DEREncodeOctetString(bt, str);198}199200bool ECP::ValidateParameters(RandomNumberGenerator &rng, unsigned int level) const201{202Integer p = FieldSize();203204bool pass = p.IsOdd();205pass = pass && !m_a.IsNegative() && m_a<p && !m_b.IsNegative() && m_b<p;206207if (level >= 1)208pass = pass && ((4*m_a*m_a*m_a+27*m_b*m_b)%p).IsPositive();209210if (level >= 2)211pass = pass && VerifyPrime(rng, p);212213return pass;214}215216bool ECP::VerifyPoint(const Point &P) const217{218const FieldElement &x = P.x, &y = P.y;219Integer p = FieldSize();220return P.identity ||221(!x.IsNegative() && x<p && !y.IsNegative() && y<p222&& !(((x*x+m_a)*x+m_b-y*y)%p));223}224225bool ECP::Equal(const Point &P, const Point &Q) const226{227if (P.identity && Q.identity)228return true;229230if (P.identity && !Q.identity)231return false;232233if (!P.identity && Q.identity)234return false;235236return (GetField().Equal(P.x,Q.x) && GetField().Equal(P.y,Q.y));237}238239const ECP::Point& ECP::Identity() const240{241#if defined(HAVE_GCC_INIT_PRIORITY) || defined(HAVE_MSC_INIT_PRIORITY) || defined(HAVE_XLC_INIT_PRIORITY)242return g_identity;243#elif defined(CRYPTOPP_CXX11_STATIC_INIT)244static const ECP::Point g_identity;245return g_identity;246#else247return Singleton<Point>().Ref();248#endif249}250251const ECP::Point& ECP::Inverse(const Point &P) const252{253if (P.identity)254return P;255else256{257m_R.identity = false;258m_R.x = P.x;259m_R.y = GetField().Inverse(P.y);260return m_R;261}262}263264const ECP::Point& ECP::Add(const Point &P, const Point &Q) const265{266if (P.identity) return Q;267if (Q.identity) return P;268if (GetField().Equal(P.x, Q.x))269return GetField().Equal(P.y, Q.y) ? Double(P) : Identity();270271FieldElement t = GetField().Subtract(Q.y, P.y);272t = GetField().Divide(t, GetField().Subtract(Q.x, P.x));273FieldElement x = GetField().Subtract(GetField().Subtract(GetField().Square(t), P.x), Q.x);274m_R.y = GetField().Subtract(GetField().Multiply(t, GetField().Subtract(P.x, x)), P.y);275276m_R.x.swap(x);277m_R.identity = false;278return m_R;279}280281const ECP::Point& ECP::Double(const Point &P) const282{283if (P.identity || P.y==GetField().Identity()) return Identity();284285FieldElement t = GetField().Square(P.x);286t = GetField().Add(GetField().Add(GetField().Double(t), t), m_a);287t = GetField().Divide(t, GetField().Double(P.y));288FieldElement x = GetField().Subtract(GetField().Subtract(GetField().Square(t), P.x), P.x);289m_R.y = GetField().Subtract(GetField().Multiply(t, GetField().Subtract(P.x, x)), P.y);290291m_R.x.swap(x);292m_R.identity = false;293return m_R;294}295296template <class T, class Iterator> void ParallelInvert(const AbstractRing<T> &ring, Iterator begin, Iterator end)297{298size_t n = end-begin;299if (n == 1)300*begin = ring.MultiplicativeInverse(*begin);301else if (n > 1)302{303std::vector<T> vec((n+1)/2);304unsigned int i;305Iterator it;306307for (i=0, it=begin; i<n/2; i++, it+=2)308vec[i] = ring.Multiply(*it, *(it+1));309if (n%2 == 1)310vec[n/2] = *it;311312ParallelInvert(ring, vec.begin(), vec.end());313314for (i=0, it=begin; i<n/2; i++, it+=2)315{316if (!vec[i])317{318*it = ring.MultiplicativeInverse(*it);319*(it+1) = ring.MultiplicativeInverse(*(it+1));320}321else322{323std::swap(*it, *(it+1));324*it = ring.Multiply(*it, vec[i]);325*(it+1) = ring.Multiply(*(it+1), vec[i]);326}327}328if (n%2 == 1)329*it = vec[n/2];330}331}332333class ProjectiveDoubling334{335public:336ProjectiveDoubling(const ModularArithmetic &m_mr, const Integer &m_a, const Integer &m_b, const ECPPoint &Q)337: mr(m_mr)338{339CRYPTOPP_UNUSED(m_b);340if (Q.identity)341{342sixteenY4 = P.x = P.y = mr.MultiplicativeIdentity();343aZ4 = P.z = mr.Identity();344}345else346{347P.x = Q.x;348P.y = Q.y;349sixteenY4 = P.z = mr.MultiplicativeIdentity();350aZ4 = m_a;351}352}353354void Double()355{356twoY = mr.Double(P.y);357P.z = mr.Multiply(P.z, twoY);358fourY2 = mr.Square(twoY);359S = mr.Multiply(fourY2, P.x);360aZ4 = mr.Multiply(aZ4, sixteenY4);361M = mr.Square(P.x);362M = mr.Add(mr.Add(mr.Double(M), M), aZ4);363P.x = mr.Square(M);364mr.Reduce(P.x, S);365mr.Reduce(P.x, S);366mr.Reduce(S, P.x);367P.y = mr.Multiply(M, S);368sixteenY4 = mr.Square(fourY2);369mr.Reduce(P.y, mr.Half(sixteenY4));370}371372const ModularArithmetic &mr;373ProjectivePoint P;374Integer sixteenY4, aZ4, twoY, fourY2, S, M;375};376377struct ZIterator378{379ZIterator() {}380ZIterator(std::vector<ProjectivePoint>::iterator it) : it(it) {}381Integer& operator*() {return it->z;}382int operator-(ZIterator it2) {return int(it-it2.it);}383ZIterator operator+(int i) {return ZIterator(it+i);}384ZIterator& operator+=(int i) {it+=i; return *this;}385std::vector<ProjectivePoint>::iterator it;386};387388ECP::Point ECP::ScalarMultiply(const Point &P, const Integer &k) const389{390Element result;391if (k.BitCount() <= 5)392AbstractGroup<ECPPoint>::SimultaneousMultiply(&result, P, &k, 1);393else394ECP::SimultaneousMultiply(&result, P, &k, 1);395return result;396}397398void ECP::SimultaneousMultiply(ECP::Point *results, const ECP::Point &P, const Integer *expBegin, unsigned int expCount) const399{400if (!GetField().IsMontgomeryRepresentation())401{402ECP ecpmr(*this, true);403const ModularArithmetic &mr = ecpmr.GetField();404ecpmr.SimultaneousMultiply(results, ToMontgomery(mr, P), expBegin, expCount);405for (unsigned int i=0; i<expCount; i++)406results[i] = FromMontgomery(mr, results[i]);407return;408}409410ProjectiveDoubling rd(GetField(), m_a, m_b, P);411std::vector<ProjectivePoint> bases;412std::vector<WindowSlider> exponents;413exponents.reserve(expCount);414std::vector<std::vector<word32> > baseIndices(expCount);415std::vector<std::vector<bool> > negateBase(expCount);416std::vector<std::vector<word32> > exponentWindows(expCount);417unsigned int i;418419for (i=0; i<expCount; i++)420{421CRYPTOPP_ASSERT(expBegin->NotNegative());422exponents.push_back(WindowSlider(*expBegin++, InversionIsFast(), 5));423exponents[i].FindNextWindow();424}425426unsigned int expBitPosition = 0;427bool notDone = true;428429while (notDone)430{431notDone = false;432bool baseAdded = false;433for (i=0; i<expCount; i++)434{435if (!exponents[i].finished && expBitPosition == exponents[i].windowBegin)436{437if (!baseAdded)438{439bases.push_back(rd.P);440baseAdded =true;441}442443exponentWindows[i].push_back(exponents[i].expWindow);444baseIndices[i].push_back((word32)bases.size()-1);445negateBase[i].push_back(exponents[i].negateNext);446447exponents[i].FindNextWindow();448}449notDone = notDone || !exponents[i].finished;450}451452if (notDone)453{454rd.Double();455expBitPosition++;456}457}458459// convert from projective to affine coordinates460ParallelInvert(GetField(), ZIterator(bases.begin()), ZIterator(bases.end()));461for (i=0; i<bases.size(); i++)462{463if (bases[i].z.NotZero())464{465bases[i].y = GetField().Multiply(bases[i].y, bases[i].z);466bases[i].z = GetField().Square(bases[i].z);467bases[i].x = GetField().Multiply(bases[i].x, bases[i].z);468bases[i].y = GetField().Multiply(bases[i].y, bases[i].z);469}470}471472std::vector<BaseAndExponent<Point, Integer> > finalCascade;473for (i=0; i<expCount; i++)474{475finalCascade.resize(baseIndices[i].size());476for (unsigned int j=0; j<baseIndices[i].size(); j++)477{478ProjectivePoint &base = bases[baseIndices[i][j]];479if (base.z.IsZero())480finalCascade[j].base.identity = true;481else482{483finalCascade[j].base.identity = false;484finalCascade[j].base.x = base.x;485if (negateBase[i][j])486finalCascade[j].base.y = GetField().Inverse(base.y);487else488finalCascade[j].base.y = base.y;489}490finalCascade[j].exponent = Integer(Integer::POSITIVE, 0, exponentWindows[i][j]);491}492results[i] = GeneralCascadeMultiplication(*this, finalCascade.begin(), finalCascade.end());493}494}495496ECP::Point ECP::CascadeScalarMultiply(const Point &P, const Integer &k1, const Point &Q, const Integer &k2) const497{498if (!GetField().IsMontgomeryRepresentation())499{500ECP ecpmr(*this, true);501const ModularArithmetic &mr = ecpmr.GetField();502return FromMontgomery(mr, ecpmr.CascadeScalarMultiply(ToMontgomery(mr, P), k1, ToMontgomery(mr, Q), k2));503}504else505return AbstractGroup<Point>::CascadeScalarMultiply(P, k1, Q, k2);506}507508NAMESPACE_END509510#endif511512513