| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043 |
- { *********************************************************************************** }
- { * CryptoLib Library * }
- { * Copyright (c) 2018 - 20XX Ugochukwu Mmaduekwe * }
- { * Github Repository <https://github.com/Xor-el> * }
- { * Distributed under the MIT software license, see the accompanying file LICENSE * }
- { * or visit http://www.opensource.org/licenses/mit-license.php. * }
- { * Acknowledgements: * }
- { * * }
- { * Thanks to Sphere 10 Software (http://www.sphere10.com/) for sponsoring * }
- { * development of this library * }
- { * ******************************************************************************* * }
- (* &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& *)
- unit ClpBigInteger;
- {$I ..\Include\CryptoLib.inc}
- interface
- uses
- Classes,
- Math,
- SysUtils,
- StrUtils,
- Generics.Collections,
- ClpNumberStyles,
- ClpISecureRandom,
- ClpIRandom,
- ClpCryptoLibTypes;
- resourcestring
- SDivisionByZero = 'Division by Zero Error';
- SModulusPositive = 'Modulus must be Positive';
- SNotRelativelyPrime = 'Numbers not Relatively Prime.';
- SNegativeValue = 'Cannot be Called on Value < 0';
- SNegativeExponent = 'Negative Exponent';
- SResultTooLarge = 'Result too Large';
- SNegativeBitPosition = 'Bit Position must not be Negative';
- SInvalidBitAddress = 'Bit Address less than Zero';
- SZeroLengthBigInteger = 'Zero length BigInteger';
- SInvalidSign = 'Invalid Sign Value';
- SNegativeSizeInBits = 'sizeInBits must be non-negative';
- SInvalidBitLength = 'bitLength < 2';
- SInvalidBase = 'Only bases 2, 8, 10, or 16 allowed';
- SBadCharacterRadix8 = 'Bad Character in radix 8 string: %s';
- SBadCharacterRadix2 = 'Bad Character in radix 2 string: %s';
- SUnSupportedBase = 'Only bases 2, 8, 10, 16 are allowed';
- type
- TBigInteger = record
- strict private
- const
- IMASK = Int64($FFFFFFFF);
- UIMASK = UInt64($FFFFFFFF);
- BitLengthTable: array [0 .. 255] of Byte = (0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4,
- 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6,
- 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
- 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8,
- 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
- 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
- 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
- 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
- 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8);
- /// <summary>
- /// These are the threshold bit-lengths (of an exponent) where we
- /// increase the window size. <br />They are calculated according to the
- /// expected savings in multiplications. <br />Some squares will also be
- /// saved on average, but we offset these against the extra storage
- /// costs. <br />
- /// </summary>
- ExpWindowThresholds: array [0 .. 7] of Int32 = (7, 25, 81, 241, 673, 1793,
- 4609, Int32($7FFFFFFF));
- // TODO Parse radix-2 64 bits at a time and radix-8 63 bits at a time
- chunk2 = Int32(1);
- chunk8 = Int32(1);
- chunk10 = Int32(19);
- chunk16 = Int32(16);
- BitsPerByte = Int32(8);
- BitsPerInt = Int32(32);
- BytesPerInt = Int32(4);
- var
- // array of ints with [0] being the most significant
- Fmagnitude: TCryptoLibInt32Array;
- Fsign: Int32; // -1 means -ve; +1 means +ve; 0 means 0;
- FnBits: Int32; // cache BitCount() value
- FnBitLength: Int32; // cache BitLength() value
- // -m^(-1) mod b, b = 2^32 (see Montgomery mult.), 0 when uninitialised
- FmQuote: Int32;
- FIsInitialized: Boolean;
- class var
- FZero, FOne, FTwo, FThree, FFour, FTen: TBigInteger;
- // Each list has a product < 2^31
- FprimeLists: TCryptoLibMatrixInt32Array;
- FprimeProducts, FZeroMagnitude: TCryptoLibInt32Array;
- FZeroEncoding: TCryptoLibByteArray;
- FSMALL_CONSTANTS: TCryptoLibGenericArray<TBigInteger>;
- Fradix2, Fradix2E, Fradix8, Fradix8E, Fradix10, Fradix10E, Fradix16,
- Fradix16E: TBigInteger;
- FRandomSource: ISecureRandom;
- function GetBitLength: Int32; inline;
- function GetBitCount: Int32; inline;
- function GetInt32Value: Int32; inline;
- function GetInt64Value: Int64; inline;
- function GetIsInitialized: Boolean; inline;
- function GetSignValue: Int32; inline;
- function AddToMagnitude(magToAdd: TCryptoLibInt32Array): TBigInteger;
- function QuickPow2Check(): Boolean; inline;
- /// <summary>
- /// return z = x / y - done in place (z value preserved, x contains the *
- /// remainder)
- /// </summary>
- function Divide(x, y: TCryptoLibInt32Array): TCryptoLibInt32Array; overload;
- function IsEqualMagnitude(const x: TBigInteger): Boolean;
- function CheckProbablePrime(certainty: Int32; const random: IRandom;
- randomlySelected: Boolean): Boolean;
- function ModInversePow2(const m: TBigInteger): TBigInteger;
- /// <summary>
- /// Calculate mQuote = -m^(-1) mod b with b = 2^32 (32 = word size)
- /// </summary>
- function GetMQuote(): Int32; inline;
- function Remainder(m: Int32): Int32; overload; inline;
- /// <summary>
- /// return x = x mod y - done in place (y value preserved)
- /// </summary>
- function Remainder(x, y: TCryptoLibInt32Array)
- : TCryptoLibInt32Array; overload;
- function LastNBits(n: Int32): TCryptoLibInt32Array; inline;
- function DivideWords(w: Int32): TBigInteger; inline;
- function RemainderWords(w: Int32): TBigInteger; inline;
- function ToByteArray(unsigned: Boolean): TCryptoLibByteArray; overload;
- function FlipExistingBit(n: Int32): TBigInteger; inline;
- function GetLowestSetBitMaskFirst(firstWordMask: Int32): Int32;
- procedure ParseString(const str: String; radix: Int32);
- procedure ParseBytes(bytes: TCryptoLibByteArray; offset, length: Int32);
- procedure ParseBytesWithSign(sign: Int32; bytes: TCryptoLibByteArray;
- offset, length: Int32);
- class function GetZero: TBigInteger; static; inline;
- class function GetOne: TBigInteger; static; inline;
- class function GetTwo: TBigInteger; static; inline;
- class function GetThree: TBigInteger; static; inline;
- class function GetFour: TBigInteger; static; inline;
- class function GetTen: TBigInteger; static; inline;
- class function GetprimeLists: TCryptoLibMatrixInt32Array; static; inline;
- class function GetprimeProducts: TCryptoLibInt32Array; static; inline;
- class function GetRandomSource: ISecureRandom; static; inline;
- class function GetByteLength(nBits: Int32): Int32; static; inline;
- class function MakeMagnitude(bytes: TCryptoLibByteArray;
- offset, length: Int32): TCryptoLibInt32Array; static;
- /// <summary>
- /// a = a + b - b preserved.
- /// </summary>
- class function AddMagnitudes(a, b: TCryptoLibInt32Array)
- : TCryptoLibInt32Array; static; inline;
- class function CalcBitLength(sign, indx: Int32; mag: TCryptoLibInt32Array)
- : Int32; static;
- /// <summary>
- /// unsigned comparison on two arrays - note the arrays may start with
- /// leading zeros.
- /// </summary>
- class function CompareTo(xIndx: Int32; x: TCryptoLibInt32Array;
- yIndx: Int32; y: TCryptoLibInt32Array): Int32; overload; static;
- class function CompareNoLeadingZeroes(xIndx: Int32; x: TCryptoLibInt32Array;
- yIndx: Int32; y: TCryptoLibInt32Array): Int32; static;
- class function ModInverse32(d: Int32): Int32; static; inline;
- class function ModInverse64(d: Int64): Int64; static; inline;
- /// <summary>
- /// Calculate the numbers u1, u2, and u3 such that: <br />u1 * a + u2 * b
- /// = u3 <br />where u3 is the greatest common divider of a and b. <br />
- /// a and b using the extended Euclid algorithm (refer p. 323 of The Art
- /// of Computer Programming vol 2, 2nd ed). <br />This also seems to have
- /// the side effect of calculating some form of multiplicative inverse.
- /// </summary>
- /// <param name="a">
- /// First number to calculate gcd for
- /// </param>
- /// <param name="b">
- /// Second number to calculate gcd for
- /// </param>
- /// <param name="u1Out">
- /// the return object for the u1 value
- /// </param>
- /// <returns>
- /// The greatest common divisor of a and b
- /// </returns>
- class function ExtEuclid(const a, b: TBigInteger; out u1Out: TBigInteger)
- : TBigInteger; static; inline;
- class function ModPowBarrett(const b, e, m: TBigInteger)
- : TBigInteger; static;
- class function ReduceBarrett(x: TBigInteger; const m, mr, yu: TBigInteger)
- : TBigInteger; static;
- class function ModPowMonty(b: TBigInteger; const e, m: TBigInteger;
- convert: Boolean): TBigInteger; static;
- class function GetWindowList(mag: TCryptoLibInt32Array; extraBits: Int32)
- : TCryptoLibInt32Array; static;
- class function CreateWindowEntry(mult, zeroes: Int32): Int32;
- static; inline;
- /// <returns>
- /// w with w = x * x - w is assumed to have enough space.
- /// </returns>
- class function Square(w, x: TCryptoLibInt32Array): TCryptoLibInt32Array;
- overload; static;
- /// <returns>
- /// x with x = y * z - x is assumed to have enough space.
- /// </returns>
- class function Multiply(x, y, z: TCryptoLibInt32Array)
- : TCryptoLibInt32Array; overload; static;
- // mDash = -m^(-1) mod b
- class procedure MontgomeryReduce(x, m: TCryptoLibInt32Array;
- mDash: UInt32); static;
- // mDash = -m^(-1) mod b
- /// <summary>
- /// Montgomery multiplication: a = x * y * R^(-1) mod m <br />Based
- /// algorithm 14.36 of Handbook of Applied Cryptography. <br /><li>
- /// m, x, y should have length n </li> <br /><li> a should
- /// have length (n + 1) </li> <br /><li> b = 2^32, R = b^n
- /// </li> <br /><br/> <br />The result is put in x <br />
- /// <br/> <br />NOTE: the indices of x, y, m, a different in HAC
- /// and in Java <br />
- /// </summary>
- class procedure MultiplyMonty(a, x, y, m: TCryptoLibInt32Array;
- mDash: UInt32; smallMontyModulus: Boolean); static;
- // mDash = -m^(-1) mod b
- class procedure SquareMonty(a, x, m: TCryptoLibInt32Array; mDash: UInt32;
- smallMontyModulus: Boolean); static;
- class function MultiplyMontyNIsOne(x, y, m, mDash: UInt32): UInt32;
- static; inline;
- /// <summary>
- /// do a left shift - this returns a new array.
- /// </summary>
- class function ShiftLeft(mag: TCryptoLibInt32Array; n: Int32)
- : TCryptoLibInt32Array; overload; static;
- /// <summary>
- /// do a right shift - this does it in place.
- /// </summary>
- class procedure ShiftRightInPlace(start: Int32; mag: TCryptoLibInt32Array;
- n: Int32); static;
- /// <summary>
- /// do a right shift by one - this does it in place.
- /// </summary>
- class procedure ShiftRightOneInPlace(start: Int32;
- mag: TCryptoLibInt32Array); static;
- /// <summary>
- /// returns x = x - y - we assume x is >= y
- /// </summary>
- class function Subtract(xStart: Int32; x: TCryptoLibInt32Array;
- yStart: Int32; y: TCryptoLibInt32Array): TCryptoLibInt32Array;
- overload; static;
- class function doSubBigLil(bigMag, lilMag: TCryptoLibInt32Array)
- : TCryptoLibInt32Array; static; inline;
- class procedure AppendZeroExtendedString(var sl: TStringList;
- const s: String; minLength: Int32); static; inline;
- class procedure ToString(sl: TStringList; radix: Int32;
- moduli: TList<TBigInteger>; scale: Int32; const pos: TBigInteger);
- overload; static;
- class function CreateUValueOf(value: UInt64): TBigInteger; static;
- class function CreateValueOf(value: Int64): TBigInteger; static;
- class function IntToBin(input: Int32): string; static;
- class function IntToOctal(input: Int32): string; static;
- constructor Create(signum: Int32; mag: TCryptoLibInt32Array;
- checkMag: Boolean); overload;
- class constructor BigInteger();
- public
- property BitLength: Int32 read GetBitLength;
- property BitCount: Int32 read GetBitCount;
- property IsInitialized: Boolean read GetIsInitialized;
- property Int32Value: Int32 read GetInt32Value;
- property Int64Value: Int64 read GetInt64Value;
- property SignValue: Int32 read GetSignValue;
- class property Zero: TBigInteger read GetZero;
- class property One: TBigInteger read GetOne;
- class property Two: TBigInteger read GetTwo;
- class property Three: TBigInteger read GetThree;
- class property Four: TBigInteger read GetFour;
- class property Ten: TBigInteger read GetTen;
- class property primeLists: TCryptoLibMatrixInt32Array read GetprimeLists;
- class property primeProducts: TCryptoLibInt32Array read GetprimeProducts;
- class property RandomSource: ISecureRandom read GetRandomSource;
- constructor Create(const value: String); overload;
- constructor Create(const str: String; radix: Int32); overload;
- constructor Create(bytes: TCryptoLibByteArray); overload;
- constructor Create(bytes: TCryptoLibByteArray;
- offset, length: Int32); overload;
- constructor Create(sign: Int32; bytes: TCryptoLibByteArray); overload;
- constructor Create(sign: Int32; bytes: TCryptoLibByteArray;
- offset, length: Int32); overload;
- constructor Create(sizeInBits: Int32; const random: IRandom); overload;
- constructor Create(BitLength, certainty: Int32;
- const random: IRandom); overload;
- function Abs(): TBigInteger;
- function Add(const value: TBigInteger): TBigInteger;
- function Subtract(const n: TBigInteger): TBigInteger; overload;
- function &And(const value: TBigInteger): TBigInteger;
- function &Not(): TBigInteger;
- function AndNot(const val: TBigInteger): TBigInteger;
- function &Or(const value: TBigInteger): TBigInteger;
- function &Xor(const value: TBigInteger): TBigInteger;
- function CompareTo(const value: TBigInteger): Int32; overload;
- function Divide(const val: TBigInteger): TBigInteger; overload;
- function DivideAndRemainder(const val: TBigInteger)
- : TCryptoLibGenericArray<TBigInteger>;
- function Gcd(const value: TBigInteger): TBigInteger;
- function Inc(): TBigInteger;
- function RabinMillerTest(certainty: Int32; const random: IRandom)
- : Boolean; overload;
- function RabinMillerTest(certainty: Int32; const random: IRandom;
- randomlySelected: Boolean): Boolean; overload;
- /// <summary>
- /// return whether or not a BigInteger is probably prime with a
- /// probability of 1 - (1/2)**certainty. <br /><p>From Knuth Vol 2,
- /// pg 395.</p>
- /// </summary>
- function IsProbablePrime(certainty: Int32): Boolean; overload;
- function IsProbablePrime(certainty: Int32; randomlySelected: Boolean)
- : Boolean; overload;
- function Max(const value: TBigInteger): TBigInteger;
- function Min(const value: TBigInteger): TBigInteger;
- function &Mod(const m: TBigInteger): TBigInteger;
- function ModInverse(const m: TBigInteger): TBigInteger;
- function ModPow(e: TBigInteger; const m: TBigInteger): TBigInteger;
- function Multiply(const val: TBigInteger): TBigInteger; overload;
- function Square(): TBigInteger; overload;
- function Negate(): TBigInteger;
- function NextProbablePrime(): TBigInteger;
- function Pow(exp: Int32): TBigInteger;
- function Remainder(const n: TBigInteger): TBigInteger; overload;
- function ShiftLeft(n: Int32): TBigInteger; overload;
- function ShiftRight(n: Int32): TBigInteger;
- function ToByteArray(): TCryptoLibByteArray; overload;
- function ToByteArrayUnsigned(): TCryptoLibByteArray;
- function TestBit(n: Int32): Boolean;
- function SetBit(n: Int32): TBigInteger;
- function ClearBit(n: Int32): TBigInteger;
- function FlipBit(n: Int32): TBigInteger;
- function GetLowestSetBit(): Int32;
- function ToString(): String; overload;
- function ToString(radix: Int32): String; overload;
- function Equals(const other: TBigInteger): Boolean; inline;
- function GetHashCode(): {$IFDEF DELPHI}Int32; {$ELSE}PtrInt;
- inline;
- {$ENDIF DELPHI}
- class function BitCnt(i: Int32): Int32; static;
- /// <summary>
- /// BitLen(value) is the number of bits in value.
- /// </summary>
- class function BitLen(w: Int32): Int32; static;
- class function ProbablePrime(BitLength: Int32; const random: IRandom)
- : TBigInteger; static;
- class function ValueOf(value: Int64): TBigInteger; static;
- class function Arbitrary(sizeInBits: Int32): TBigInteger; static;
- class function Jacobi(const a, b: TBigInteger): Int32; static;
- class procedure Boot(); static;
- end;
- implementation
- uses
- ClpSecureRandom; // included here to avoid circular dependency :)
- { TBigInteger }
- class function TBigInteger.BitLen(w: Int32): Int32;
- var
- v, t: UInt32;
- begin
- v := UInt32(w);
- t := v shr 24;
- if (t <> 0) then
- begin
- Result := 24 + BitLengthTable[t];
- Exit;
- end;
- t := v shr 16;
- if (t <> 0) then
- begin
- Result := 16 + BitLengthTable[t];
- Exit;
- end;
- t := v shr 8;
- if (t <> 0) then
- begin
- Result := 8 + BitLengthTable[t];
- Exit;
- end;
- Result := BitLengthTable[v];
- end;
- class function TBigInteger.CalcBitLength(sign, indx: Int32;
- mag: TCryptoLibInt32Array): Int32;
- var
- BitLength, firstMag: Int32;
- begin
- while True do
- begin
- if (indx >= System.length(mag)) then
- begin
- Result := 0;
- Exit;
- end;
- if (mag[indx] <> 0) then
- begin
- break;
- end;
- System.Inc(indx);
- end;
- // bit length for everything after the first int
- BitLength := 32 * ((System.length(mag) - indx) - 1);
- // and determine bitlength of first int
- firstMag := mag[indx];
- BitLength := BitLength + BitLen(firstMag);
- // Check for negative powers of two
- if ((sign < 0) and ((firstMag and Int32(-firstMag)) = firstMag)) then
- begin
- repeat
- System.Inc(indx);
- if (indx >= System.length(mag)) then
- begin
- System.Dec(BitLength);
- break;
- end;
- until (not(mag[indx] = 0));
- end;
- Result := BitLength;
- end;
- class function TBigInteger.GetZero: TBigInteger;
- begin
- Result := FZero;
- end;
- class function TBigInteger.GetOne: TBigInteger;
- begin
- Result := FOne;
- end;
- class function TBigInteger.GetTwo: TBigInteger;
- begin
- Result := FTwo;
- end;
- class function TBigInteger.GetThree: TBigInteger;
- begin
- Result := FThree;
- end;
- class function TBigInteger.GetFour: TBigInteger;
- begin
- Result := FFour;
- end;
- class function TBigInteger.GetTen: TBigInteger;
- begin
- Result := FTen;
- end;
- class function TBigInteger.GetprimeLists: TCryptoLibMatrixInt32Array;
- begin
- Result := FprimeLists;
- end;
- class function TBigInteger.GetprimeProducts: TCryptoLibInt32Array;
- begin
- Result := FprimeProducts;
- end;
- class function TBigInteger.GetRandomSource: ISecureRandom;
- begin
- Result := FRandomSource;
- end;
- function TBigInteger.GetSignValue: Int32;
- begin
- Result := Fsign;
- end;
- function TBigInteger.GetBitLength: Int32;
- begin
- if (FnBitLength = -1) then
- begin
- if Fsign = 0 then
- begin
- FnBitLength := 0;
- end
- else
- begin
- FnBitLength := CalcBitLength(Fsign, 0, Fmagnitude);
- end;
- end;
- Result := FnBitLength;
- end;
- function TBigInteger.GetInt32Value: Int32;
- var
- n, v: Int32;
- begin
- if (Fsign = 0) then
- begin
- Result := 0;
- Exit;
- end;
- n := System.length(Fmagnitude);
- v := Fmagnitude[n - 1];
- if Fsign < 0 then
- begin
- Result := -v;
- end
- else
- begin
- Result := v;
- end;
- end;
- function TBigInteger.GetInt64Value: Int64;
- var
- n: Int32;
- v: Int64;
- begin
- if (Fsign = 0) then
- begin
- Result := 0;
- Exit;
- end;
- n := System.length(Fmagnitude);
- v := Fmagnitude[n - 1] and IMASK;
- if (n > 1) then
- begin
- v := v or ((Fmagnitude[n - 2] and IMASK) shl 32);
- end;
- if Fsign < 0 then
- begin
- Result := -v;
- Exit;
- end
- else
- begin
- Result := v;
- Exit;
- end;
- end;
- function TBigInteger.GetIsInitialized: Boolean;
- begin
- Result := FIsInitialized;
- end;
- class function TBigInteger.BitCnt(i: Int32): Int32;
- var
- u: UInt32;
- begin
- u := UInt32(i);
- {$IFDEF FPC}
- Result := Int32(PopCnt(u));
- {$ELSE}
- u := u - ((u shr 1) and $55555555);
- u := (u and $33333333) + ((u shr 2) and $33333333);
- u := (u + (u shr 4)) and $0F0F0F0F;
- u := u + (u shr 8);
- u := u + (u shr 16);
- u := u and $3F;
- Result := Int32(u);
- {$ENDIF FPC}
- end;
- class function TBigInteger.CreateWindowEntry(mult, zeroes: Int32): Int32;
- begin
- while ((mult and 1) = 0) do
- begin
- mult := mult shr 1;
- System.Inc(zeroes);
- end;
- Result := mult or (zeroes shl 8);
- end;
- class function TBigInteger.GetByteLength(nBits: Int32): Int32;
- begin
- Result := (nBits + BitsPerByte - 1) div BitsPerByte;
- end;
- function TBigInteger.LastNBits(n: Int32): TCryptoLibInt32Array;
- var
- numWords, excessBits: Int32;
- begin
- if (n < 1) then
- begin
- Result := FZeroMagnitude;
- Exit;
- end;
- numWords := (n + BitsPerInt - 1) div BitsPerInt;
- numWords := Math.Min(numWords, System.length(Fmagnitude));
- System.SetLength(Result, numWords);
- System.Move(Fmagnitude[System.length(Fmagnitude) - numWords], Result[0],
- numWords * System.SizeOf(Int32));
- excessBits := (numWords shl 5) - n;
- if (excessBits > 0) then
- begin
- Result[0] := Result[0] and (Int32(System.High(UInt32) shr excessBits));
- end;
- end;
- function TBigInteger.CompareTo(const value: TBigInteger): Int32;
- begin
- if Fsign < value.Fsign then
- begin
- Result := -1;
- end
- else
- begin
- if Fsign > value.Fsign then
- begin
- Result := 1;
- end
- else
- begin
- if Fsign = 0 then
- begin
- Result := 0
- end
- else
- begin
- Result := Fsign * CompareNoLeadingZeroes(0, Fmagnitude, 0,
- value.Fmagnitude);
- end;
- end;
- end;
- end;
- class function TBigInteger.CreateValueOf(value: Int64): TBigInteger;
- begin
- if (value < 0) then
- begin
- if (value = System.Low(Int64)) then
- begin
- Result := CreateValueOf(not value).&Not();
- Exit;
- end;
- Result := CreateValueOf(-value).Negate();
- Exit;
- end;
- Result := CreateUValueOf(UInt64(value));
- end;
- class function TBigInteger.CreateUValueOf(value: UInt64): TBigInteger;
- var
- msw, lsw: Int32;
- begin
- msw := Int32(value shr 32);
- lsw := Int32(value);
- if (msw <> 0) then
- begin
- Result := TBigInteger.Create(1, TCryptoLibInt32Array.Create(msw,
- lsw), false);
- Exit;
- end;
- if (lsw <> 0) then
- begin
- Result := TBigInteger.Create(1, TCryptoLibInt32Array.Create(lsw), false);
- // Check for a power of two
- if ((lsw and -lsw) = lsw) then
- begin
- Result.FnBits := 1;
- end;
- Exit;
- end;
- Result := Zero;
- end;
- class function TBigInteger.ValueOf(value: Int64): TBigInteger;
- begin
- if ((value >= 0) and (value < System.length(FSMALL_CONSTANTS))) then
- begin
- Result := FSMALL_CONSTANTS[value];
- Exit;
- end;
- Result := CreateValueOf(value);
- end;
- class procedure TBigInteger.Boot;
- var
- i: UInt32;
- primeList: TCryptoLibInt32Array;
- product, j: Int32;
- begin
- System.SetLength(FZeroEncoding, 0);
- System.SetLength(FZeroMagnitude, 0);
- FprimeLists := TCryptoLibMatrixInt32Array.Create
- (TCryptoLibInt32Array.Create(3, 5, 7, 11, 13, 17, 19, 23),
- TCryptoLibInt32Array.Create(29, 31, 37, 41, 43),
- TCryptoLibInt32Array.Create(47, 53, 59, 61, 67),
- TCryptoLibInt32Array.Create(71, 73, 79, 83), TCryptoLibInt32Array.Create(89,
- 97, 101, 103),
- TCryptoLibInt32Array.Create(107, 109, 113, 127),
- TCryptoLibInt32Array.Create(131, 137, 139, 149),
- TCryptoLibInt32Array.Create(151, 157, 163, 167),
- TCryptoLibInt32Array.Create(173, 179, 181, 191),
- TCryptoLibInt32Array.Create(193, 197, 199, 211),
- TCryptoLibInt32Array.Create(223, 227, 229), TCryptoLibInt32Array.Create(233,
- 239, 241), TCryptoLibInt32Array.Create(251, 257, 263),
- TCryptoLibInt32Array.Create(269, 271, 277), TCryptoLibInt32Array.Create(281,
- 283, 293),
- TCryptoLibInt32Array.Create(307, 311, 313), TCryptoLibInt32Array.Create(317,
- 331, 337), TCryptoLibInt32Array.Create(347, 349, 353),
- TCryptoLibInt32Array.Create(359, 367, 373), TCryptoLibInt32Array.Create(379,
- 383, 389),
- TCryptoLibInt32Array.Create(397, 401, 409), TCryptoLibInt32Array.Create(419,
- 421, 431), TCryptoLibInt32Array.Create(433, 439, 443),
- TCryptoLibInt32Array.Create(449, 457, 461), TCryptoLibInt32Array.Create(463,
- 467, 479),
- TCryptoLibInt32Array.Create(487, 491, 499), TCryptoLibInt32Array.Create(503,
- 509, 521), TCryptoLibInt32Array.Create(523, 541, 547),
- TCryptoLibInt32Array.Create(557, 563, 569), TCryptoLibInt32Array.Create(571,
- 577, 587),
- TCryptoLibInt32Array.Create(593, 599, 601), TCryptoLibInt32Array.Create(607,
- 613, 617), TCryptoLibInt32Array.Create(619, 631, 641),
- TCryptoLibInt32Array.Create(643, 647, 653), TCryptoLibInt32Array.Create(659,
- 661, 673),
- TCryptoLibInt32Array.Create(677, 683, 691), TCryptoLibInt32Array.Create(701,
- 709, 719), TCryptoLibInt32Array.Create(727, 733, 739),
- TCryptoLibInt32Array.Create(743, 751, 757), TCryptoLibInt32Array.Create(761,
- 769, 773),
- TCryptoLibInt32Array.Create(787, 797, 809), TCryptoLibInt32Array.Create(811,
- 821, 823), TCryptoLibInt32Array.Create(827, 829, 839),
- TCryptoLibInt32Array.Create(853, 857, 859), TCryptoLibInt32Array.Create(863,
- 877, 881),
- TCryptoLibInt32Array.Create(883, 887, 907), TCryptoLibInt32Array.Create(911,
- 919, 929), TCryptoLibInt32Array.Create(937, 941, 947),
- TCryptoLibInt32Array.Create(953, 967, 971), TCryptoLibInt32Array.Create(977,
- 983, 991),
- TCryptoLibInt32Array.Create(997, 1009, 1013),
- TCryptoLibInt32Array.Create(1019, 1021, 1031),
- TCryptoLibInt32Array.Create(1033, 1039, 1049),
- TCryptoLibInt32Array.Create(1051, 1061, 1063),
- TCryptoLibInt32Array.Create(1069, 1087, 1091),
- TCryptoLibInt32Array.Create(1093, 1097, 1103),
- TCryptoLibInt32Array.Create(1109, 1117, 1123),
- TCryptoLibInt32Array.Create(1129, 1151, 1153),
- TCryptoLibInt32Array.Create(1163, 1171, 1181),
- TCryptoLibInt32Array.Create(1187, 1193, 1201),
- TCryptoLibInt32Array.Create(1213, 1217, 1223),
- TCryptoLibInt32Array.Create(1229, 1231, 1237),
- TCryptoLibInt32Array.Create(1249, 1259, 1277),
- TCryptoLibInt32Array.Create(1279, 1283, 1289));
- //TSecureRandom.Boot;
- FRandomSource := TSecureRandom.Create();
- FZero := TBigInteger.Create(0, FZeroMagnitude, false);
- FZero.FnBits := 0;
- FZero.FnBitLength := 0;
- System.SetLength(FSMALL_CONSTANTS, 17);
- FSMALL_CONSTANTS[0] := FZero;
- i := 1;
- while i < UInt32(System.length(FSMALL_CONSTANTS)) do
- begin
- FSMALL_CONSTANTS[i] := CreateUValueOf(i);
- System.Inc(i);
- end;
- FOne := FSMALL_CONSTANTS[1];
- FTwo := FSMALL_CONSTANTS[2];
- FThree := FSMALL_CONSTANTS[3];
- FFour := FSMALL_CONSTANTS[4];
- FTen := FSMALL_CONSTANTS[10];
- Fradix2 := ValueOf(2);
- Fradix2E := Fradix2.Pow(chunk2);
- Fradix8 := ValueOf(8);
- Fradix8E := Fradix8.Pow(chunk8);
- Fradix10 := ValueOf(10);
- Fradix10E := Fradix10.Pow(chunk10);
- Fradix16 := ValueOf(16);
- Fradix16E := Fradix16.Pow(chunk16);
- System.SetLength(FprimeProducts, System.length(primeLists));
- for i := 0 to System.Pred(System.length(primeLists)) do
- begin
- primeList := primeLists[i];
- product := primeList[0];
- for j := 1 to System.Pred(System.length(primeList)) do
- begin
- product := product * primeList[j];
- end;
- FprimeProducts[i] := product;
- end;
- end;
- function TBigInteger.QuickPow2Check: Boolean;
- begin
- Result := (Fsign > 0) and (FnBits = 1);
- end;
- function TBigInteger.Negate: TBigInteger;
- begin
- if (Fsign = 0) then
- begin
- Result := Self;
- Exit;
- end;
- Result := TBigInteger.Create(-Fsign, Fmagnitude, false);
- end;
- class function TBigInteger.doSubBigLil(bigMag, lilMag: TCryptoLibInt32Array)
- : TCryptoLibInt32Array;
- var
- res: TCryptoLibInt32Array;
- begin
- res := System.Copy(bigMag);
- Result := Subtract(0, res, 0, lilMag);
- end;
- function TBigInteger.Inc: TBigInteger;
- begin
- if (Fsign = 0) then
- begin
- Result := One;
- Exit;
- end;
- if (Fsign < 0) then
- begin
- Result := TBigInteger.Create(-1, doSubBigLil(Fmagnitude,
- One.Fmagnitude), True);
- Exit;
- end;
- Result := AddToMagnitude(One.Fmagnitude);
- end;
- class function TBigInteger.IntToBin(input: Int32): string;
- var
- bits: TCryptoLibCharArray;
- i: Int32;
- begin
- Result := '';
- System.SetLength(bits, System.SizeOf(Int32) * 8);
- i := 0;
- while (input <> 0) do
- begin
- if (input and 1) = 1 then
- begin
- bits[i] := '1'
- end
- else
- begin
- bits[i] := '0';
- end;
- System.Inc(i);
- input := input shr 1;
- end;
- System.SetString(Result, PChar(@bits[0]), i);
- Result := ReverseString(Result);
- end;
- class function TBigInteger.IntToOctal(input: Int32): string;
- var
- bits: TCryptoLibCharArray;
- i: Int32;
- begin
- Result := '';
- System.SetLength(bits, System.SizeOf(Int32) * 8);
- i := 0;
- while (input <> 0) do
- begin
- case (input and 7) of
- 0:
- bits[i] := '0';
- 1:
- bits[i] := '1';
- 2:
- bits[i] := '2';
- 3:
- bits[i] := '3';
- 4:
- bits[i] := '4';
- 5:
- bits[i] := '5';
- 6:
- bits[i] := '6';
- 7:
- bits[i] := '7';
- end;
- System.Inc(i);
- input := input shr 3;
- end;
- System.SetString(Result, PChar(@bits[0]), i);
- Result := ReverseString(Result);
- end;
- function TBigInteger.&Not: TBigInteger;
- begin
- Result := Inc().Negate();
- end;
- function TBigInteger.TestBit(n: Int32): Boolean;
- var
- wordNum, word: Int32;
- begin
- if (n < 0) then
- begin
- raise EArithmeticCryptoLibException.CreateRes(@SNegativeBitPosition);
- end;
- if (Fsign < 0) then
- begin
- Result := (not &Not().TestBit(n));
- Exit;
- end;
- wordNum := n div 32;
- if (wordNum >= System.length(Fmagnitude)) then
- begin
- Result := false;
- Exit;
- end;
- word := Fmagnitude[System.length(Fmagnitude) - 1 - wordNum];
- Result := ((word shr (n and 31)) and 1) > 0;
- end;
- function TBigInteger.Abs: TBigInteger;
- begin
- if Fsign >= 0 then
- begin
- Result := Self;
- end
- else
- begin
- Result := Negate();
- end;
- end;
- function TBigInteger.Square: TBigInteger;
- var
- resLength: Int32;
- res: TCryptoLibInt32Array;
- begin
- if (Fsign = 0) then
- begin
- Result := Zero;
- Exit;
- end;
- if (QuickPow2Check()) then
- begin
- Result := ShiftLeft(Abs().BitLength - 1);
- Exit;
- end;
- resLength := System.length(Fmagnitude) shl 1;
- if (UInt32(Fmagnitude[0]) shr 16 = 0) then
- begin
- System.Dec(resLength);
- end;
- System.SetLength(res, resLength);
- Square(res, Fmagnitude);
- Result := TBigInteger.Create(1, res, false);
- end;
- function TBigInteger.Add(const value: TBigInteger): TBigInteger;
- begin
- if (Fsign = 0) then
- begin
- Result := value;
- Exit;
- end;
- if (Fsign <> value.Fsign) then
- begin
- if (value.Fsign = 0) then
- begin
- Result := Self;
- Exit;
- end;
- if (value.Fsign < 0) then
- begin
- Result := Subtract(value.Negate());
- Exit;
- end;
- Result := value.Subtract(Negate());
- Exit;
- end;
- Result := AddToMagnitude(value.Fmagnitude);
- end;
- class function TBigInteger.AddMagnitudes(a, b: TCryptoLibInt32Array)
- : TCryptoLibInt32Array;
- var
- tI, vI: Int32;
- m: Int64;
- begin
- tI := System.length(a) - 1;
- vI := System.length(b) - 1;
- m := 0;
- while (vI >= 0) do
- begin
- m := m + (Int64(UInt32(a[tI])) + Int64(UInt32(b[vI])));
- System.Dec(vI);
- a[tI] := Int32(m);
- System.Dec(tI);
- m := Int64(UInt64(m shr 32));
- end;
- if (m <> 0) then
- begin
- while (tI >= 0) do
- begin
- a[tI] := a[tI] + 1;
- if (a[tI] <> 0) then
- begin
- break;
- end;
- System.Dec(tI);
- end;
- end;
- Result := a;
- end;
- function TBigInteger.AddToMagnitude(magToAdd: TCryptoLibInt32Array)
- : TBigInteger;
- var
- big, small, bigCopy: TCryptoLibInt32Array;
- limit: UInt32;
- possibleOverflow: Boolean;
- begin
- if (System.length(Fmagnitude) < System.length(magToAdd)) then
- begin
- big := magToAdd;
- small := Fmagnitude;
- end
- else
- begin
- big := Fmagnitude;
- small := magToAdd;
- end;
- // Conservatively avoid over-allocation when no overflow possible
- limit := System.High(UInt32);
- if (System.length(big) = System.length(small)) then
- begin
- limit := limit - UInt32(small[0]);
- end;
- possibleOverflow := UInt32(big[0]) >= limit;
- if (possibleOverflow) then
- begin
- System.SetLength(bigCopy, System.length(big) + 1);
- System.Move(big[0], bigCopy[1], System.length(big) * System.SizeOf(Int32));
- end
- else
- begin
- bigCopy := System.Copy(big);
- end;
- bigCopy := AddMagnitudes(bigCopy, small);
- Result := TBigInteger.Create(Fsign, bigCopy, possibleOverflow);
- end;
- function TBigInteger.&And(const value: TBigInteger): TBigInteger;
- var
- aMag, bMag, resultMag: TCryptoLibInt32Array;
- resultNeg: Boolean;
- resultLength, aStart, bStart, i, aWord, bWord: Int32;
- begin
- if ((Fsign = 0) or (value.Fsign = 0)) then
- begin
- Result := Zero;
- Exit;
- end;
- if Fsign > 0 then
- begin
- aMag := Fmagnitude;
- end
- else
- begin
- aMag := Add(One).Fmagnitude;
- end;
- if value.Fsign > 0 then
- begin
- bMag := value.Fmagnitude;
- end
- else
- begin
- bMag := value.Add(One).Fmagnitude;
- end;
- resultNeg := (Fsign < 0) and (value.Fsign < 0);
- resultLength := Math.Max(System.length(aMag), System.length(bMag));
- System.SetLength(resultMag, resultLength);
- aStart := System.length(resultMag) - System.length(aMag);
- bStart := System.length(resultMag) - System.length(bMag);
- for i := 0 to System.Pred(System.length(resultMag)) do
- begin
- if i >= aStart then
- begin
- aWord := aMag[i - aStart];
- end
- else
- begin
- aWord := 0;
- end;
- if i >= bStart then
- begin
- bWord := bMag[i - bStart];
- end
- else
- begin
- bWord := 0;
- end;
- if (Fsign < 0) then
- begin
- aWord := not aWord;
- end;
- if (value.Fsign < 0) then
- begin
- bWord := not bWord;
- end;
- resultMag[i] := aWord and bWord;
- if (resultNeg) then
- begin
- resultMag[i] := not resultMag[i];
- end;
- end;
- Result := TBigInteger.Create(1, resultMag, True);
- // TODO Optimise this case
- if (resultNeg) then
- begin
- Result := Result.&Not();
- end;
- end;
- function TBigInteger.AndNot(const val: TBigInteger): TBigInteger;
- begin
- Result := &And(val.&Not());
- end;
- class procedure TBigInteger.AppendZeroExtendedString(var sl: TStringList;
- const s: String; minLength: Int32);
- var
- len: Int32;
- begin
- len := System.length(s);
- while len < minLength do
- begin
- sl.Add('0');
- System.Inc(len);
- end;
- sl.Add(s);
- end;
- class procedure TBigInteger.ToString(sl: TStringList; radix: Int32;
- moduli: TList<TBigInteger>; scale: Int32; const pos: TBigInteger);
- var
- s: String;
- qr: TCryptoLibGenericArray<TBigInteger>;
- begin
- if (pos.BitLength < 64) then
- begin
- s := IntToStr(pos.Int64Value);
- if ((sl.Count > 1) or ((sl.Count = 1) and (sl[0] <> '-'))) then
- begin
- AppendZeroExtendedString(sl, s, 1 shl scale);
- end
- else if (pos.SignValue <> 0) then
- begin
- sl.Append(s);
- end;
- Exit;
- end;
- System.Dec(scale);
- qr := pos.DivideAndRemainder(moduli[scale]);
- ToString(sl, radix, moduli, scale, qr[0]);
- ToString(sl, radix, moduli, scale, qr[1]);
- end;
- class function TBigInteger.Arbitrary(sizeInBits: Int32): TBigInteger;
- begin
- Result := TBigInteger.Create(sizeInBits, RandomSource);
- end;
- function TBigInteger.Remainder(m: Int32): Int32;
- var
- acc, posVal: Int64;
- &pos: Int32;
- begin
- {$IFDEF DEBUG}
- System.Assert(m > 0);
- {$ENDIF DEBUG}
- acc := 0;
- for pos := 0 to System.Pred(System.length(Fmagnitude)) do
- begin
- posVal := UInt32(Fmagnitude[pos]);
- acc := ((acc shl 32) or posVal) mod m;
- end;
- Result := Int32(acc);
- end;
- function TBigInteger.Remainder(const n: TBigInteger): TBigInteger;
- var
- val, rem: Int32;
- tempRes: TCryptoLibInt32Array;
- begin
- if (n.Fsign = 0) then
- begin
- raise EArithmeticCryptoLibException.CreateRes(@SDivisionByZero);
- end;
- if (Fsign = 0) then
- begin
- Result := Zero;
- Exit;
- end;
- // For small values, use fast remainder method
- if (System.length(n.Fmagnitude) = 1) then
- begin
- val := n.Fmagnitude[0];
- if (val > 0) then
- begin
- if (val = 1) then
- begin
- Result := Zero;
- Exit;
- end;
- // TODO Make this func work on uint, and handle val == 1?
- rem := Remainder(val);
- if rem = 0 then
- begin
- Result := Zero;
- Exit;
- end
- else
- begin
- Result := TBigInteger.Create(Fsign,
- TCryptoLibInt32Array.Create(rem), false);
- Exit;
- end;
- end;
- end;
- if (CompareNoLeadingZeroes(0, Fmagnitude, 0, n.Fmagnitude) < 0) then
- begin
- Result := Self;
- Exit;
- end;
- if (n.QuickPow2Check()) then // n is power of two
- begin
- // TODO Move before small values branch above?
- tempRes := LastNBits(n.Abs().BitLength - 1);
- end
- else
- begin
- tempRes := System.Copy(Fmagnitude);
- tempRes := Remainder(tempRes, n.Fmagnitude);
- end;
- Result := TBigInteger.Create(Fsign, tempRes, True);
- end;
- function TBigInteger.&Mod(const m: TBigInteger): TBigInteger;
- var
- biggie: TBigInteger;
- begin
- if (m.Fsign < 1) then
- begin
- raise EArithmeticCryptoLibException.CreateRes(@SModulusPositive);
- end;
- biggie := Remainder(m);
- if biggie.Fsign >= 0 then
- begin
- Result := biggie;
- end
- else
- begin
- Result := biggie.Add(m);
- end;
- end;
- function TBigInteger.&Or(const value: TBigInteger): TBigInteger;
- var
- aMag, bMag, resultMag: TCryptoLibInt32Array;
- resultNeg: Boolean;
- resultLength, aStart, bStart, i, aWord, bWord: Int32;
- begin
- if (Fsign = 0) then
- begin
- Result := value;
- Exit;
- end;
- if (value.Fsign = 0) then
- begin
- Result := Self;
- Exit;
- end;
- if Fsign > 0 then
- begin
- aMag := Fmagnitude;
- end
- else
- begin
- aMag := Add(One).Fmagnitude;
- end;
- if value.Fsign > 0 then
- begin
- bMag := value.Fmagnitude;
- end
- else
- begin
- bMag := value.Add(One).Fmagnitude;
- end;
- resultNeg := (Fsign < 0) or (value.Fsign < 0);
- resultLength := Math.Max(System.length(aMag), System.length(bMag));
- System.SetLength(resultMag, resultLength);
- aStart := System.length(resultMag) - System.length(aMag);
- bStart := System.length(resultMag) - System.length(bMag);
- for i := 0 to System.Pred(System.length(resultMag)) do
- begin
- if i >= aStart then
- begin
- aWord := aMag[i - aStart];
- end
- else
- begin
- aWord := 0;
- end;
- if i >= bStart then
- begin
- bWord := bMag[i - bStart];
- end
- else
- begin
- bWord := 0;
- end;
- if (Fsign < 0) then
- begin
- aWord := not aWord;
- end;
- if (value.Fsign < 0) then
- begin
- bWord := not bWord;
- end;
- resultMag[i] := aWord or bWord;
- if (resultNeg) then
- begin
- resultMag[i] := not resultMag[i];
- end;
- end;
- Result := TBigInteger.Create(1, resultMag, True);
- // TODO Optimise this case
- if (resultNeg) then
- begin
- Result := Result.&Not();
- end;
- end;
- function TBigInteger.&Xor(const value: TBigInteger): TBigInteger;
- var
- aMag, bMag, resultMag: TCryptoLibInt32Array;
- resultNeg: Boolean;
- resultLength, aStart, bStart, i, aWord, bWord: Int32;
- begin
- if (Fsign = 0) then
- begin
- Result := value;
- Exit;
- end;
- if (value.Fsign = 0) then
- begin
- Result := Self;
- Exit;
- end;
- if Fsign > 0 then
- begin
- aMag := Fmagnitude;
- end
- else
- begin
- aMag := Add(One).Fmagnitude;
- end;
- if value.Fsign > 0 then
- begin
- bMag := value.Fmagnitude;
- end
- else
- begin
- bMag := value.Add(One).Fmagnitude;
- end;
- // TODO Can just replace with sign != value.sign?
- resultNeg := ((Fsign < 0) and (value.Fsign >= 0)) or
- ((Fsign >= 0) and (value.Fsign < 0));
- resultLength := Math.Max(System.length(aMag), System.length(bMag));
- System.SetLength(resultMag, resultLength);
- aStart := System.length(resultMag) - System.length(aMag);
- bStart := System.length(resultMag) - System.length(bMag);
- for i := 0 to System.Pred(System.length(resultMag)) do
- begin
- if i >= aStart then
- begin
- aWord := aMag[i - aStart];
- end
- else
- begin
- aWord := 0;
- end;
- if i >= bStart then
- begin
- bWord := bMag[i - bStart];
- end
- else
- begin
- bWord := 0;
- end;
- if (Fsign < 0) then
- begin
- aWord := not aWord;
- end;
- if (value.Fsign < 0) then
- begin
- bWord := not bWord;
- end;
- resultMag[i] := aWord xor bWord;
- if (resultNeg) then
- begin
- resultMag[i] := not resultMag[i];
- end;
- end;
- Result := TBigInteger.Create(1, resultMag, True);
- // TODO Optimise this case
- if (resultNeg) then
- begin
- Result := Result.&Not();
- end;
- end;
- class constructor TBigInteger.BigInteger;
- begin
- TBigInteger.Boot;
- end;
- constructor TBigInteger.Create(const value: String);
- begin
- ParseString(value, 10);
- end;
- constructor TBigInteger.Create(const str: String; radix: Int32);
- begin
- ParseString(str, radix);
- end;
- constructor TBigInteger.Create(bytes: TCryptoLibByteArray);
- begin
- ParseBytes(bytes, 0, System.length(bytes));
- end;
- constructor TBigInteger.Create(sign: Int32; bytes: TCryptoLibByteArray);
- begin
- ParseBytesWithSign(sign, bytes, 0, System.length(bytes));
- end;
- constructor TBigInteger.Create(bytes: TCryptoLibByteArray;
- offset, length: Int32);
- begin
- ParseBytes(bytes, offset, length);
- end;
- constructor TBigInteger.Create(sign: Int32; bytes: TCryptoLibByteArray;
- offset, length: Int32);
- begin
- ParseBytesWithSign(sign, bytes, offset, length);
- end;
- constructor TBigInteger.Create(BitLength, certainty: Int32;
- const random: IRandom);
- var
- nBytes, xBits, j: Int32;
- mask, lead: Byte;
- b: TCryptoLibByteArray;
- begin
- if (BitLength < 2) then
- begin
- raise EArithmeticCryptoLibException.CreateRes(@SInvalidBitLength);
- end;
- Fsign := 1;
- FnBits := -1;
- FnBitLength := BitLength;
- FmQuote := 0;
- FIsInitialized := True;
- if (BitLength = 2) then
- begin
- if (random.Next(2) = 0) then
- begin
- Fmagnitude := Two.Fmagnitude
- end
- else
- begin
- Fmagnitude := Three.Fmagnitude
- end;
- Exit;
- end;
- nBytes := GetByteLength(BitLength);
- System.SetLength(b, nBytes);
- xBits := (BitsPerByte * nBytes) - BitLength;
- mask := Byte(UInt32(255) shr xBits);
- lead := Byte(1 shl (7 - xBits));
- while True do
- begin
- random.NextBytes(b);
- // strip off any excess bits in the MSB
- b[0] := b[0] and mask;
- // ensure the leading bit is 1 (to meet the strength requirement)
- b[0] := b[0] or lead;
- // ensure the trailing bit is 1 (i.e. must be odd)
- b[nBytes - 1] := b[nBytes - 1] or 1;
- Fmagnitude := MakeMagnitude(b, 0, System.length(b));
- FnBits := -1;
- FmQuote := 0;
- if (certainty < 1) then
- begin
- break;
- end;
- if (CheckProbablePrime(certainty, random, True)) then
- begin
- break;
- end;
- j := 1;
- while j < (System.length(Fmagnitude) - 1) do
- begin
- Fmagnitude[j] := Fmagnitude[j] xor random.Next();
- if (CheckProbablePrime(certainty, random, True)) then
- begin
- Exit;
- end;
- System.Inc(j);
- end;
- end;
- end;
- constructor TBigInteger.Create(sizeInBits: Int32; const random: IRandom);
- var
- nBytes, xBits: Int32;
- b: TCryptoLibByteArray;
- begin
- if (sizeInBits < 0) then
- begin
- raise EArgumentCryptoLibException.CreateRes(@SNegativeSizeInBits);
- end;
- Fsign := -1;
- FnBits := -1;
- FnBitLength := -1;
- FmQuote := 0;
- FIsInitialized := True;
- if (sizeInBits = 0) then
- begin
- Fsign := 0;
- Fmagnitude := FZeroMagnitude;
- Exit;
- end;
- nBytes := GetByteLength(sizeInBits);
- System.SetLength(b, nBytes);
- random.NextBytes(b);
- // strip off any excess bits in the MSB
- xBits := (BitsPerByte * nBytes) - sizeInBits;
- b[0] := b[0] and Byte(UInt32(255) shr xBits);
- Fmagnitude := MakeMagnitude(b, 0, System.length(b));
- if System.length(Fmagnitude) < 1 then
- begin
- Fsign := 0;
- end
- else
- begin
- Fsign := 1;
- end;
- end;
- constructor TBigInteger.Create(signum: Int32; mag: TCryptoLibInt32Array;
- checkMag: Boolean);
- var
- i: Int32;
- begin
- Fsign := -1;
- FnBits := -1;
- FnBitLength := -1;
- FmQuote := 0;
- FIsInitialized := True;
- if (checkMag) then
- begin
- i := 0;
- while ((i < System.length(mag)) and (mag[i] = 0)) do
- begin
- System.Inc(i);
- end;
- if (i = System.length(mag)) then
- begin
- Fsign := 0;
- Fmagnitude := FZeroMagnitude;
- end
- else
- begin
- Fsign := signum;
- if (i = 0) then
- begin
- Fmagnitude := mag;
- end
- else
- begin
- // strip leading 0 words
- System.SetLength(Fmagnitude, System.length(mag) - i);
- System.Move(mag[i], Fmagnitude[0], System.length(Fmagnitude) *
- System.SizeOf(Int32));
- end
- end;
- end
- else
- begin
- Fsign := signum;
- Fmagnitude := mag;
- end;
- end;
- function TBigInteger.Equals(const other: TBigInteger): Boolean;
- begin
- Result := (Fsign = other.Fsign) and IsEqualMagnitude(other);
- end;
- class function TBigInteger.ExtEuclid(const a, b: TBigInteger;
- out u1Out: TBigInteger): TBigInteger;
- var
- u1, v1, u3, v3, oldU1: TBigInteger;
- q: TCryptoLibGenericArray<TBigInteger>;
- begin
- u1 := One;
- v1 := Zero;
- u3 := a;
- v3 := b;
- if (v3.Fsign > 0) then
- begin
- while True do
- begin
- q := u3.DivideAndRemainder(v3);
- u3 := v3;
- v3 := q[1];
- oldU1 := u1;
- u1 := v1;
- if (v3.Fsign <= 0) then
- begin
- break;
- end;
- v1 := oldU1.Subtract(v1.Multiply(q[0]));
- end;
- end;
- u1Out := u1;
- Result := u3;
- end;
- function TBigInteger.FlipExistingBit(n: Int32): TBigInteger;
- var
- mag: TCryptoLibInt32Array;
- begin
- {$IFDEF DEBUG}
- System.Assert(Fsign > 0);
- System.Assert(n >= 0);
- System.Assert(n < BitLength - 1);
- {$ENDIF DEBUG}
- mag := System.Copy(Fmagnitude);
- mag[System.length(mag) - 1 - (n shr 5)] :=
- mag[System.length(mag) - 1 - (n shr 5)] xor (1 shl (n and 31));
- // Flip bit
- // mag[mag.Length - 1 - (n / 32)] ^= (1 << (n % 32));
- Result := TBigInteger.Create(Fsign, mag, false);
- end;
- function TBigInteger.FlipBit(n: Int32): TBigInteger;
- begin
- if (n < 0) then
- begin
- raise EArithmeticCryptoLibException.CreateRes(@SInvalidBitAddress);
- end;
- // TODO Handle negative values and zero
- if ((Fsign > 0) and (n < (BitLength - 1))) then
- begin
- Result := FlipExistingBit(n);
- Exit;
- end;
- Result := &Xor(One.ShiftLeft(n));
- end;
- function TBigInteger.Gcd(const value: TBigInteger): TBigInteger;
- var
- r, u, v: TBigInteger;
- begin
- if (value.Fsign = 0) then
- begin
- Result := Abs();
- Exit;
- end;
- if (Fsign = 0) then
- begin
- Result := value.Abs();
- Exit;
- end;
- u := Self;
- v := value;
- while (v.Fsign <> 0) do
- begin
- r := u.&Mod(v);
- u := v;
- v := r;
- end;
- Result := u;
- end;
- function TBigInteger.GetBitCount: Int32;
- var
- sum, i: Int32;
- begin
- if (FnBits = -1) then
- begin
- if (Fsign < 0) then
- begin
- // TODO Optimise this case
- FnBits := &Not().BitCount;
- end
- else
- begin
- sum := 0;
- for i := 0 to System.Pred(System.length(Fmagnitude)) do
- begin
- sum := sum + BitCnt(Fmagnitude[i]);
- end;
- FnBits := sum;
- end;
- end;
- Result := FnBits;
- end;
- function TBigInteger.GetHashCode: {$IFDEF DELPHI}Int32; {$ELSE}PtrInt;
- {$ENDIF DELPHI}
- var
- hc: Int32;
- begin
- hc := System.length(Fmagnitude);
- if (System.length(Fmagnitude) > 0) then
- begin
- hc := hc xor Fmagnitude[0];
- if (System.length(Fmagnitude) > 1) then
- begin
- hc := hc xor Fmagnitude[System.length(Fmagnitude) - 1];
- end;
- end;
- if Fsign < 0 then
- begin
- Result := not hc;
- end
- else
- begin
- Result := hc;
- end;
- end;
- function TBigInteger.GetLowestSetBit: Int32;
- begin
- if (Fsign = 0) then
- begin
- Result := -1;
- Exit;
- end;
- Result := GetLowestSetBitMaskFirst(-1);
- end;
- function TBigInteger.GetLowestSetBitMaskFirst(firstWordMask: Int32): Int32;
- var
- w, offset: Int32;
- word: UInt32;
- begin
- w := System.length(Fmagnitude);
- offset := 0;
- System.Dec(w);
- word := UInt32(Fmagnitude[w] and firstWordMask);
- {$IFDEF DEBUG}
- System.Assert(Fmagnitude[0] <> 0);
- {$ENDIF DEBUG}
- while (word = 0) do
- begin
- System.Dec(w);
- word := UInt32(Fmagnitude[w]);
- offset := offset + 32;
- end;
- while ((word and $FF) = 0) do
- begin
- word := word shr 8;
- offset := offset + 8;
- end;
- while ((word and 1) = 0) do
- begin
- word := word shr 1;
- System.Inc(offset);
- end;
- Result := offset;
- end;
- class function TBigInteger.ModInverse32(d: Int32): Int32;
- var
- x: Int32;
- begin
- // Newton's method with initial estimate "correct to 4 bits"
- {$IFDEF DEBUG}
- System.Assert((d and 1) <> 0);
- {$ENDIF DEBUG}
- x := d + (((d + 1) and 4) shl 1); // d.x == 1 mod 2**4
- {$IFDEF DEBUG}
- System.Assert(((d * x) and 15) = 1);
- {$ENDIF DEBUG}
- x := x * (2 - (d * x)); // d.x == 1 mod 2**8
- x := x * (2 - (d * x)); // d.x == 1 mod 2**16
- x := x * (2 - (d * x)); // d.x == 1 mod 2**32
- {$IFDEF DEBUG}
- System.Assert(d * x = 1);
- {$ENDIF DEBUG}
- Result := x;
- end;
- function TBigInteger.GetMQuote: Int32;
- var
- d: Int32;
- begin
- if (FmQuote <> 0) then
- begin
- Result := FmQuote; // already calculated
- Exit;
- end;
- {$IFDEF DEBUG}
- System.Assert(Fsign > 0);
- {$ENDIF DEBUG}
- d := Int32(Fmagnitude[System.length(Fmagnitude) - 1]);
- d := -d;
- {$IFDEF DEBUG}
- System.Assert((d and 1) <> 0);
- {$ENDIF DEBUG}
- FmQuote := ModInverse32(d);
- Result := FmQuote;
- end;
- function TBigInteger.IsEqualMagnitude(const x: TBigInteger): Boolean;
- var
- i: Integer;
- xMag: TCryptoLibInt32Array;
- begin
- xMag := x.Fmagnitude;
- if (System.length(Fmagnitude) <> System.length(xMag)) then
- begin
- Result := false;
- Exit;
- end;
- for i := 0 to System.Pred(System.length(Fmagnitude)) do
- begin
- if (Fmagnitude[i] <> xMag[i]) then
- begin
- Result := false;
- Exit;
- end;
- end;
- Result := True;
- end;
- function TBigInteger.IsProbablePrime(certainty: Int32;
- randomlySelected: Boolean): Boolean;
- var
- n: TBigInteger;
- begin
- if (certainty <= 0) then
- begin
- Result := True;
- Exit;
- end;
- n := Abs();
- if (not n.TestBit(0)) then
- begin
- Result := n.Equals(Two);
- Exit;
- end;
- if (n.Equals(One)) then
- begin
- Result := false;
- Exit;
- end;
- Result := n.CheckProbablePrime(certainty, RandomSource, randomlySelected);
- end;
- class function TBigInteger.Jacobi(const a, b: TBigInteger): Int32;
- var
- totalS, e, bLsw, a1Lsw: Int32;
- a1, La, Lb: TBigInteger;
- begin
- La := a;
- Lb := b;
- {$IFDEF DEBUG}
- System.Assert(La.SignValue >= 0);
- System.Assert(Lb.SignValue > 0);
- System.Assert(Lb.TestBit(0));
- System.Assert(La.CompareTo(Lb) < 0);
- {$ENDIF DEBUG}
- totalS := 1;
- while True do
- begin
- if (La.SignValue = 0) then
- begin
- Result := 0;
- Exit;
- end;
- if (La.Equals(One)) then
- begin
- break;
- end;
- e := La.GetLowestSetBit();
- bLsw := Lb.Fmagnitude[System.length(Lb.Fmagnitude) - 1];
- if (((e and 1) <> 0) and (((bLsw and 7) = 3) or ((bLsw and 7) = 5))) then
- begin
- totalS := -totalS;
- end;
- if (La.BitLength = e + 1) then
- begin
- break;
- end;
- a1 := La.ShiftRight(e);
- a1Lsw := a1.Fmagnitude[System.length(a1.Fmagnitude) - 1];
- if (((bLsw and 3) = 3) and ((a1Lsw and 3) = 3)) then
- begin
- totalS := -totalS;
- end;
- La := Lb.Remainder(a1);
- Lb := a1;
- end;
- Result := totalS;
- end;
- function TBigInteger.IsProbablePrime(certainty: Int32): Boolean;
- begin
- Result := IsProbablePrime(certainty, false);
- end;
- class function TBigInteger.MakeMagnitude(bytes: TCryptoLibByteArray;
- offset, length: Int32): TCryptoLibInt32Array;
- var
- endPoint, firstSignificant, nInts, bCount, v, magnitudeIndex, i: Int32;
- mag: TCryptoLibInt32Array;
- begin
- endPoint := offset + length;
- // strip leading zeros
- firstSignificant := offset;
- while ((firstSignificant < endPoint) and (bytes[firstSignificant] = 0)) do
- begin
- System.Inc(firstSignificant);
- end;
- if (firstSignificant >= endPoint) then
- begin
- Result := FZeroMagnitude;
- Exit;
- end;
- nInts := (endPoint - firstSignificant + 3) div BytesPerInt;
- bCount := (endPoint - firstSignificant) mod BytesPerInt;
- if (bCount = 0) then
- begin
- bCount := BytesPerInt;
- end;
- if (nInts < 1) then
- begin
- Result := FZeroMagnitude;
- Exit;
- end;
- System.SetLength(mag, nInts);
- v := 0;
- magnitudeIndex := 0;
- i := firstSignificant;
- while i < endPoint do
- begin
- v := v shl 8;
- v := v or (bytes[i] and $FF);
- System.Dec(bCount);
- if (bCount <= 0) then
- begin
- mag[magnitudeIndex] := v;
- System.Inc(magnitudeIndex);
- bCount := BytesPerInt;
- v := 0;
- end;
- System.Inc(i);
- end;
- if (magnitudeIndex < System.length(mag)) then
- begin
- mag[magnitudeIndex] := v;
- end;
- Result := mag;
- end;
- function TBigInteger.Max(const value: TBigInteger): TBigInteger;
- begin
- if CompareTo(value) > 0 then
- begin
- Result := Self;
- end
- else
- begin
- Result := value;
- end;
- end;
- function TBigInteger.Min(const value: TBigInteger): TBigInteger;
- begin
- if CompareTo(value) < 0 then
- begin
- Result := Self;
- end
- else
- begin
- Result := value;
- end;
- end;
- function TBigInteger.ModInverse(const m: TBigInteger): TBigInteger;
- var
- d, x, Gcd: TBigInteger;
- begin
- if (m.Fsign < 1) then
- begin
- raise EArithmeticCryptoLibException.CreateRes(@SModulusPositive);
- end;
- // TODO Too slow at the moment
- // // "Fast Key Exchange with Elliptic Curve Systems" R.Schoeppel
- // if (m.TestBit(0))
- // {
- // //The Almost Inverse Algorithm
- // int k = 0;
- // BigInteger B = One, C = Zero, F = this, G = m, tmp;
- //
- // for (;;)
- // {
- // // While F is even, do F=F/u, C=C*u, k=k+1.
- // int zeroes = F.GetLowestSetBit();
- // if (zeroes > 0)
- // {
- // F = F.ShiftRight(zeroes);
- // C = C.ShiftLeft(zeroes);
- // k += zeroes;
- // }
- //
- // // If F = 1, then return B,k.
- // if (F.Equals(One))
- // {
- // BigInteger half = m.Add(One).ShiftRight(1);
- // BigInteger halfK = half.ModPow(BigInteger.ValueOf(k), m);
- // return B.Multiply(halfK).Mod(m);
- // }
- //
- // if (F.CompareTo(G) < 0)
- // {
- // tmp = G; G = F; F = tmp;
- // tmp = B; B = C; C = tmp;
- // }
- //
- // F = F.Add(G);
- // B = B.Add(C);
- // }
- // }
- if (m.QuickPow2Check()) then
- begin
- Result := ModInversePow2(m);
- Exit;
- end;
- d := Remainder(m);
- Gcd := ExtEuclid(d, m, x);
- if (not Gcd.Equals(One)) then
- begin
- raise EArithmeticCryptoLibException.CreateRes(@SNotRelativelyPrime);
- end;
- if (x.Fsign < 0) then
- begin
- x := x.Add(m);
- end;
- Result := x;
- end;
- class function TBigInteger.ModInverse64(d: Int64): Int64;
- var
- x: Int64;
- begin
- // Newton's method with initial estimate "correct to 4 bits"
- {$IFDEF DEBUG}
- System.Assert((d and Int64(1)) <> 0);
- {$ENDIF DEBUG}
- x := d + (((d + Int64(1)) and Int64(4)) shl 1); // d.x == 1 mod 2**4
- {$IFDEF DEBUG}
- System.Assert(((d * x) and Int64(15)) = Int64(1));
- {$ENDIF DEBUG}
- x := x * (2 - (d * x)); // d.x == 1 mod 2**8
- x := x * (2 - (d * x)); // d.x == 1 mod 2**16
- x := x * (2 - (d * x)); // d.x == 1 mod 2**32
- x := x * (2 - (d * x)); // d.x == 1 mod 2**64
- {$IFDEF DEBUG}
- System.Assert(d * x = Int64(1));
- {$ENDIF DEBUG}
- Result := x;
- end;
- function TBigInteger.ModInversePow2(const m: TBigInteger): TBigInteger;
- var
- Pow, bitsCorrect: Int32;
- inv64: Int64;
- x, d, t: TBigInteger;
- begin
- {$IFDEF DEBUG}
- System.Assert(m.SignValue > 0);
- System.Assert(m.BitCount = 1);
- {$ENDIF DEBUG}
- if (not TestBit(0)) then
- begin
- raise EArithmeticCryptoLibException.CreateRes(@SNotRelativelyPrime);
- end;
- Pow := m.BitLength - 1;
- inv64 := ModInverse64(Int64Value);
- if (Pow < 64) then
- begin
- inv64 := inv64 and ((Int64(1) shl Pow) - 1);
- end;
- x := TBigInteger.ValueOf(inv64);
- if (Pow > 64) then
- begin
- d := Remainder(m);
- bitsCorrect := 64;
- repeat
- t := x.Multiply(d).Remainder(m);
- x := x.Multiply(Two.Subtract(t)).Remainder(m);
- bitsCorrect := bitsCorrect shl 1;
- until (not(bitsCorrect < Pow));
- end;
- if (x.Fsign < 0) then
- begin
- x := x.Add(m);
- end;
- Result := x;
- end;
- function TBigInteger.ModPow(e: TBigInteger; const m: TBigInteger): TBigInteger;
- var
- negExp: Boolean;
- begin
- if (m.Fsign < 1) then
- begin
- raise EArithmeticCryptoLibException.CreateRes(@SModulusPositive);
- end;
- if (m.Equals(One)) then
- begin
- Result := Zero;
- Exit;
- end;
- if (e.Fsign = 0) then
- begin
- Result := One;
- Exit;
- end;
- if (Fsign = 0) then
- begin
- Result := Zero;
- Exit;
- end;
- negExp := e.Fsign < 0;
- if (negExp) then
- begin
- e := e.Negate();
- end;
- Result := &Mod(m);
- if (not e.Equals(One)) then
- begin
- if ((m.Fmagnitude[System.length(m.Fmagnitude) - 1] and 1) = 0) then
- begin
- Result := ModPowBarrett(Result, e, m);
- end
- else
- begin
- Result := ModPowMonty(Result, e, m, True);
- end;
- end;
- if (negExp) then
- begin
- Result := Result.ModInverse(m);
- end;
- end;
- class function TBigInteger.ModPowBarrett(const b, e, m: TBigInteger)
- : TBigInteger;
- var
- k, extraBits, expLength, numPowers, i, window, mult, lastZeroes, windowPos,
- bits, j: Int32;
- mr, yu, b2, y: TBigInteger;
- oddPowers: TCryptoLibGenericArray<TBigInteger>;
- windowList: TCryptoLibInt32Array;
- begin
- k := System.length(m.Fmagnitude);
- mr := One.ShiftLeft((k + 1) shl 5);
- yu := One.ShiftLeft(k shl 6).Divide(m);
- // Sliding window from MSW to LSW
- extraBits := 0;
- expLength := e.BitLength;
- while (expLength > ExpWindowThresholds[extraBits]) do
- begin
- System.Inc(extraBits);
- end;
- numPowers := 1 shl extraBits;
- System.SetLength(oddPowers, numPowers);
- oddPowers[0] := b;
- b2 := ReduceBarrett(b.Square(), m, mr, yu);
- for i := 1 to System.Pred(numPowers) do
- begin
- oddPowers[i] := ReduceBarrett(oddPowers[i - 1].Multiply(b2), m, mr, yu);
- end;
- windowList := GetWindowList(e.Fmagnitude, extraBits);
- {$IFDEF DEBUG}
- System.Assert(System.length(windowList) > 0);
- {$ENDIF DEBUG}
- window := windowList[0];
- mult := window and $FF;
- lastZeroes := window shr 8;
- if (mult = 1) then
- begin
- y := b2;
- System.Dec(lastZeroes);
- end
- else
- begin
- y := oddPowers[mult shr 1];
- end;
- windowPos := 1;
- window := windowList[windowPos];
- System.Inc(windowPos);
- while (window <> -1) do
- begin
- mult := window and $FF;
- bits := lastZeroes + BitLengthTable[mult];
- j := 0;
- while j < bits do
- begin
- y := ReduceBarrett(y.Square(), m, mr, yu);
- System.Inc(j);
- end;
- y := ReduceBarrett(y.Multiply(oddPowers[mult shr 1]), m, mr, yu);
- lastZeroes := window shr 8;
- window := windowList[windowPos];
- System.Inc(windowPos);
- end;
- i := 0;
- while i < lastZeroes do
- begin
- y := ReduceBarrett(y.Square(), m, mr, yu);
- System.Inc(i);
- end;
- Result := y;
- end;
- class function TBigInteger.ModPowMonty(b: TBigInteger; const e, m: TBigInteger;
- convert: Boolean): TBigInteger;
- var
- n, powR, extraBits, expLength, numPowers, i, window, mult, lastZeroes,
- windowPos, bits, j: Int32;
- smallMontyModulus: Boolean;
- mDash: UInt32;
- yAccum, zVal, tmp, zSquared, windowList, yVal: TCryptoLibInt32Array;
- oddPowers: TCryptoLibMatrixInt32Array;
- begin
- n := System.length(m.Fmagnitude);
- powR := 32 * n;
- smallMontyModulus := (m.BitLength + 2) <= powR;
- mDash := UInt32(m.GetMQuote());
- // tmp = this * R mod m
- if (convert) then
- begin
- b := b.ShiftLeft(powR).Remainder(m);
- end;
- System.SetLength(yAccum, n + 1);
- zVal := b.Fmagnitude;
- {$IFDEF DEBUG}
- System.Assert(System.length(zVal) <= n);
- {$ENDIF DEBUG}
- if (System.length(zVal) < n) then
- begin
- System.SetLength(tmp, n);
- System.Move(zVal[0], tmp[n - System.length(zVal)],
- System.length(zVal) * System.SizeOf(Int32));
- zVal := tmp;
- end;
- // Sliding window from MSW to LSW
- extraBits := 0;
- // Filter the common case of small RSA exponents with few bits set
- if ((System.length(e.Fmagnitude) > 1) or (e.BitCount > 2)) then
- begin
- expLength := e.BitLength;
- while (expLength > ExpWindowThresholds[extraBits]) do
- begin
- System.Inc(extraBits);
- end;
- end;
- numPowers := 1 shl extraBits;
- System.SetLength(oddPowers, numPowers);
- oddPowers[0] := zVal;
- zSquared := System.Copy(zVal, 0, System.length(zVal));
- SquareMonty(yAccum, zSquared, m.Fmagnitude, mDash, smallMontyModulus);
- for i := 1 to System.Pred(numPowers) do
- begin
- oddPowers[i] := System.Copy(oddPowers[i - 1]);
- MultiplyMonty(yAccum, oddPowers[i], zSquared, m.Fmagnitude, mDash,
- smallMontyModulus);
- end;
- windowList := GetWindowList(e.Fmagnitude, extraBits);
- {$IFDEF DEBUG}
- System.Assert(System.length(windowList) > 1);
- {$ENDIF DEBUG}
- window := windowList[0];
- mult := window and $FF;
- lastZeroes := window shr 8;
- if (mult = 1) then
- begin
- yVal := zSquared;
- System.Dec(lastZeroes);
- end
- else
- begin
- yVal := System.Copy(oddPowers[mult shr 1]);
- end;
- windowPos := 1;
- window := windowList[windowPos];
- System.Inc(windowPos);
- while (Int32(window) <> Int32(-1)) do
- begin
- mult := window and $FF;
- bits := lastZeroes + BitLengthTable[mult];
- j := 0;
- while j < bits do
- begin
- SquareMonty(yAccum, yVal, m.Fmagnitude, mDash, smallMontyModulus);
- System.Inc(j);
- end;
- MultiplyMonty(yAccum, yVal, oddPowers[mult shr 1], m.Fmagnitude, mDash,
- smallMontyModulus);
- lastZeroes := window shr 8;
- window := windowList[windowPos];
- System.Inc(windowPos);
- end;
- i := 0;
- while i < lastZeroes do
- begin
- SquareMonty(yAccum, yVal, m.Fmagnitude, mDash, smallMontyModulus);
- System.Inc(i);
- end;
- if (convert) then
- begin
- // Return y * R^(-1) mod m
- MontgomeryReduce(yVal, m.Fmagnitude, mDash);
- end
- else if ((smallMontyModulus) and (CompareTo(0, yVal, 0, m.Fmagnitude) >= 0))
- then
- begin
- Subtract(0, yVal, 0, m.Fmagnitude);
- end;
- Result := TBigInteger.Create(1, yVal, True);
- end;
- class function TBigInteger.Subtract(xStart: Int32; x: TCryptoLibInt32Array;
- yStart: Int32; y: TCryptoLibInt32Array): TCryptoLibInt32Array;
- var
- iT, iV, borrow: Int32;
- m: Int64;
- begin
- {$IFDEF DEBUG}
- System.Assert(yStart < System.length(y));
- System.Assert(System.length(x) - xStart >= System.length(y) - yStart);
- {$ENDIF DEBUG}
- iT := System.length(x);
- iV := System.length(y);
- borrow := 0;
- repeat
- System.Dec(iT);
- System.Dec(iV);
- m := (x[iT] and IMASK) - ((y[iV] and IMASK) + borrow);
- // fixed precedence bug :)
- x[iT] := Int32(m);
- // borrow = (m < 0) ? -1 : 0;
- borrow := Int32(m shr 63);
- until (not(iV > yStart));
- if (borrow <> 0) then
- begin
- System.Dec(iT);
- x[iT] := x[iT] - 1;
- while (x[iT] = -1) do
- begin
- System.Dec(iT);
- x[iT] := x[iT] - 1;
- end;
- end;
- Result := x;
- end;
- class procedure TBigInteger.MontgomeryReduce(x, m: TCryptoLibInt32Array;
- mDash: UInt32);
- var
- n, i, j: Int32;
- x0: UInt32;
- t, carry: UInt64;
- begin
- // NOTE: Not a general purpose reduction (which would allow x up to twice the bitlength of m)
- {$IFDEF DEBUG}
- System.Assert(System.length(x) = System.length(m));
- {$ENDIF DEBUG}
- n := System.length(m);
- i := n - 1;
- while i >= 0 do
- begin
- x0 := UInt32(x[n - 1]);
- t := UInt32(UInt64(x0) * mDash);
- carry := t * UInt32(m[n - 1]) + x0;
- {$IFDEF DEBUG}
- System.Assert(UInt32(carry) = 0);
- {$ENDIF DEBUG}
- carry := carry shr 32;
- j := n - 2;
- while j >= 0 do
- begin
- carry := carry + (t * UInt32(m[j]) + UInt32(x[j]));
- x[j + 1] := Int32(carry);
- carry := carry shr 32;
- System.Dec(j);
- end;
- x[0] := Int32(carry);
- {$IFDEF DEBUG}
- System.Assert(carry shr 32 = 0);
- {$ENDIF DEBUG}
- System.Dec(i);
- end;
- if (CompareTo(0, x, 0, m) >= 0) then
- begin
- Subtract(0, x, 0, m);
- end;
- end;
- class function TBigInteger.Multiply(x, y, z: TCryptoLibInt32Array)
- : TCryptoLibInt32Array;
- var
- i, xBase, j: Int32;
- a, val: Int64;
- begin
- i := System.length(z);
- if (i < 1) then
- begin
- Result := x;
- Exit;
- end;
- xBase := System.length(x) - System.length(y);
- repeat
- System.Dec(i);
- a := z[i] and IMASK;
- val := 0;
- if (a <> 0) then
- begin
- j := System.length(y) - 1;
- while j >= 0 do
- begin
- val := val + (a * (y[j] and IMASK) + (x[xBase + j] and IMASK));
- x[xBase + j] := Int32(val);
- val := Int64(UInt64(val) shr 32);
- System.Dec(j);
- end;
- end;
- System.Dec(xBase);
- if (xBase >= 0) then
- begin
- x[xBase] := Int32(val);
- end
- else
- begin
- {$IFDEF DEBUG}
- System.Assert(val = 0);
- {$ENDIF DEBUG}
- end;
- until (not(i > 0));
- Result := x;
- end;
- function TBigInteger.Multiply(const val: TBigInteger): TBigInteger;
- var
- resLength, resSign: Int32;
- res: TCryptoLibInt32Array;
- begin
- if (val.Equals(Self)) then
- begin
- Result := Square();
- Exit;
- end;
- if ((Fsign and val.Fsign) = 0) then
- begin
- Result := Zero;
- Exit;
- end;
- if (val.QuickPow2Check()) then // val is power of two
- begin
- Result := ShiftLeft(val.Abs().BitLength - 1);
- if val.Fsign > 0 then
- begin
- Exit;
- end
- else
- begin
- Result := Result.Negate();
- Exit;
- end;
- end;
- if (QuickPow2Check()) then // this is power of two
- begin
- Result := val.ShiftLeft(Abs().BitLength - 1);
- if Fsign > 0 then
- begin
- Exit;
- end
- else
- begin
- Result := Result.Negate();
- Exit;
- end;
- end;
- resLength := System.length(Fmagnitude) + System.length(val.Fmagnitude);
- System.SetLength(res, resLength);
- Multiply(res, Fmagnitude, val.Fmagnitude);
- resSign := Fsign xor val.Fsign xor 1;
- Result := TBigInteger.Create(resSign, res, True);
- end;
- class function TBigInteger.MultiplyMontyNIsOne(x, y, m, mDash: UInt32): UInt32;
- var
- carry, um, prod2: UInt64;
- t: UInt32;
- begin
- carry := UInt64(UInt64(x) * y);
- t := UInt32(UInt32(carry) * mDash);
- um := m;
- prod2 := um * t;
- carry := carry + UInt32(prod2);
- {$IFDEF DEBUG}
- System.Assert(UInt32(carry) = 0);
- {$ENDIF DEBUG}
- carry := (carry shr 32) + (prod2 shr 32);
- if (carry > um) then
- begin
- carry := carry - um;
- end;
- {$IFDEF DEBUG}
- System.Assert(carry < um);
- {$ENDIF DEBUG}
- Result := UInt32(carry);
- end;
- class procedure TBigInteger.MultiplyMonty(a, x, y, m: TCryptoLibInt32Array;
- mDash: UInt32; smallMontyModulus: Boolean);
- var
- n, aMax, j, i: Int32;
- a0, y0: UInt32;
- carry, t, prod1, prod2, xi: UInt64;
- begin
- // mDash = -m^(-1) mod b
- n := System.length(m);
- if (n = 1) then
- begin
- x[0] := Int32(MultiplyMontyNIsOne(UInt32(x[0]), UInt32(y[0]),
- UInt32(m[0]), mDash));
- Exit;
- end;
- y0 := UInt32(y[n - 1]);
- xi := UInt32(x[n - 1]);
- carry := xi * y0;
- t := UInt32(UInt64(UInt32(carry)) * mDash);
- prod2 := t * UInt32(m[n - 1]);
- carry := carry + UInt32(prod2);
- {$IFDEF DEBUG}
- System.Assert(UInt32(carry) = 0);
- {$ENDIF DEBUG}
- carry := (carry shr 32) + (prod2 shr 32);
- j := n - 2;
- while j >= 0 do
- begin
- prod1 := xi * UInt32(y[j]);
- prod2 := t * UInt32(m[j]);
- carry := carry + ((prod1 and UIMASK) + UInt32(prod2));
- a[j + 2] := Int32(carry);
- carry := (carry shr 32) + (prod1 shr 32) + (prod2 shr 32);
- System.Dec(j);
- end;
- a[1] := Int32(carry);
- aMax := Int32(carry shr 32);
- i := n - 2;
- while i >= 0 do
- begin
- a0 := UInt32(a[n]);
- xi := UInt32(x[i]);
- prod1 := xi * y0;
- carry := (prod1 and UIMASK) + a0;
- t := UInt32(UInt64(UInt32(carry)) * mDash);
- prod2 := t * UInt32(m[n - 1]);
- carry := carry + UInt32(prod2);
- {$IFDEF DEBUG}
- System.Assert(UInt32(carry) = 0);
- {$ENDIF DEBUG}
- carry := (carry shr 32) + (prod1 shr 32) + (prod2 shr 32);
- j := n - 2;
- while j >= 0 do
- begin
- prod1 := xi * UInt32(y[j]);
- prod2 := t * UInt32(m[j]);
- carry := carry + ((prod1 and UIMASK) + UInt32(prod2) + UInt32(a[j + 1]));
- a[j + 2] := Int32(carry);
- carry := (carry shr 32) + (prod1 shr 32) + (prod2 shr 32);
- System.Dec(j);
- end;
- carry := carry + UInt32(aMax);
- a[1] := Int32(carry);
- aMax := Int32(carry shr 32);
- System.Dec(i);
- end;
- a[0] := aMax;
- if ((not smallMontyModulus) and (CompareTo(0, a, 0, m) >= 0)) then
- begin
- Subtract(0, a, 0, m);
- end;
- System.Move(a[1], x[0], n * System.SizeOf(Int32));
- end;
- function TBigInteger.NextProbablePrime: TBigInteger;
- var
- n: TBigInteger;
- begin
- if (Fsign < 0) then
- begin
- raise EArithmeticCryptoLibException.CreateRes(@SNegativeValue);
- end;
- if (CompareTo(Two) < 0) then
- begin
- Result := Two;
- Exit;
- end;
- n := Inc().SetBit(0);
- while (not n.CheckProbablePrime(100, RandomSource, false)) do
- begin
- n := n.Add(Two);
- end;
- Result := n;
- end;
- procedure TBigInteger.ParseBytes(bytes: TCryptoLibByteArray;
- offset, length: Int32);
- var
- endPoint, iBval, numBytes, index: Int32;
- inverse: TCryptoLibByteArray;
- begin
- if (length = 0) then
- begin
- raise EFormatCryptoLibException.CreateRes(@SZeroLengthBigInteger);
- end;
- Fsign := -1;
- FnBits := -1;
- FnBitLength := -1;
- FmQuote := 0;
- FIsInitialized := True;
- // TODO Move this processing into MakeMagnitude (provide sign argument)
- if (ShortInt(bytes[offset]) < 0) then
- begin
- Fsign := -1;
- endPoint := offset + length;
- iBval := offset;
- // strip leading sign bytes
- while (iBval < endPoint) and (ShortInt(bytes[iBval]) = -1) do
- begin
- System.Inc(iBval);
- end;
- if (iBval >= endPoint) then
- begin
- Fmagnitude := One.Fmagnitude;
- end
- else
- begin
- numBytes := endPoint - iBval;
- System.SetLength(inverse, numBytes);
- index := 0;
- while (index < numBytes) do
- begin
- inverse[index] := Byte(not bytes[iBval]);
- System.Inc(index);
- System.Inc(iBval);
- end;
- {$IFDEF DEBUG}
- System.Assert(iBval = endPoint);
- {$ENDIF DEBUG}
- System.Dec(index);
- while (inverse[index] = System.High(Byte)) do
- begin
- inverse[index] := System.Low(Byte);
- System.Dec(index);
- end;
- inverse[index] := Byte(inverse[index] + 1);
- Fmagnitude := MakeMagnitude(inverse, 0, System.length(inverse));
- end
- end
- else
- begin
- // strip leading zero bytes and return magnitude bytes
- Fmagnitude := MakeMagnitude(bytes, offset, length);
- if System.length(Fmagnitude) > 0 then
- begin
- Fsign := 1;
- end
- else
- begin
- Fsign := 0;
- end;
- end;
- end;
- procedure TBigInteger.ParseBytesWithSign(sign: Int32;
- bytes: TCryptoLibByteArray; offset, length: Int32);
- begin
- begin
- if ((sign < -1) or (sign > 1)) then
- begin
- raise EFormatCryptoLibException.CreateRes(@SInvalidSign);
- end;
- Fsign := -1;
- FnBits := -1;
- FnBitLength := -1;
- FmQuote := 0;
- FIsInitialized := True;
- if (sign = 0) then
- begin
- Fsign := 0;
- Fmagnitude := FZeroMagnitude;
- end
- else
- begin
- // copy bytes
- Fmagnitude := MakeMagnitude(bytes, offset, length);
- if System.length(Fmagnitude) < 1 then
- begin
- Fsign := 0;
- end
- else
- begin
- Fsign := sign;
- end;
- end;
- end;
- end;
- procedure TBigInteger.ParseString(const str: String; radix: Int32);
- var
- style: TNumberStyles;
- chunk, index, Next, LowPoint, HighPoint: Int32;
- r, rE, b, bi: TBigInteger;
- dVal, s, temp: String;
- i: UInt64;
- begin
- if (System.length(str) = 0) then
- begin
- raise EFormatCryptoLibException.CreateRes(@SZeroLengthBigInteger);
- end;
- Fsign := -1;
- FnBits := -1;
- FnBitLength := -1;
- FmQuote := 0;
- FIsInitialized := True;
- case radix of
- 2:
- begin
- // Is there anyway to restrict to binary digits?
- style := TNumberStyles.Integer;
- chunk := chunk2;
- r := Fradix2;
- rE := Fradix2E;
- end;
- 8:
- begin
- // Is there anyway to restrict to octal digits?
- style := TNumberStyles.Integer;
- chunk := chunk8;
- r := Fradix8;
- rE := Fradix8E;
- end;
- 10:
- begin
- // This style seems to handle spaces and minus sign already (our processing redundant?)
- style := TNumberStyles.Integer;
- chunk := chunk10;
- r := Fradix10;
- rE := Fradix10E;
- end;
- 16:
- begin
- // TODO Should this be HexNumber?
- style := TNumberStyles.AllowHexSpecifier;
- chunk := chunk16;
- r := Fradix16;
- rE := Fradix16E;
- end
- else
- begin
- raise EFormatCryptoLibException.CreateRes(@SInvalidBase);
- end;
- end;
- {$IFDEF DELPHIXE3_UP}
- LowPoint := System.Low(str);
- HighPoint := System.High(str);
- {$ELSE}
- LowPoint := 1;
- HighPoint := System.length(str);
- {$ENDIF DELPHIXE3_UP}
- index := LowPoint;
- Fsign := 1;
- if (str[LowPoint] = '-') then
- begin
- if (HighPoint = 1) then
- begin
- raise EFormatCryptoLibException.CreateRes(@SZeroLengthBigInteger);
- end;
- Fsign := -1;
- index := LowPoint + 1;
- end;
- // strip leading zeros from the string str
- while (index < (HighPoint + 1)) do
- begin
- dVal := str[index];
- if (style = TNumberStyles.AllowHexSpecifier) then
- begin
- temp := '$' + dVal;
- end
- else
- begin
- temp := dVal;
- end;
- if (StrToInt(temp) = 0) then
- begin
- System.Inc(index);
- end
- else
- begin
- break;
- end;
- end;
- if (index >= (HighPoint + 1)) then
- begin
- // zero value - we're done
- Fsign := 0;
- Fmagnitude := FZeroMagnitude;
- Exit;
- end;
- /// ///
- // could we work out the max number of ints required to store
- // str.Length digits in the given base, then allocate that
- // storage in one hit?, then Generate the magnitude in one hit too?
- /// ///
- b := Zero;
- Next := index + chunk;
- while (Next <= (HighPoint + 1)) do
- begin
- s := System.Copy(str, index, chunk);
- if (style = TNumberStyles.AllowHexSpecifier) then
- begin
- temp := '$' + s;
- end
- else
- begin
- temp := s;
- end;
- {$IFDEF FPC}
- i := StrToQWord(temp);
- {$ELSE}
- i := StrToUInt64(temp);
- {$ENDIF FPC}
- bi := CreateUValueOf(i);
- case (radix) of
- 2:
- begin
- // TODO Need this because we are parsing in radix 10 above
- if (i >= 2) then
- begin
- raise EFormatCryptoLibException.CreateResFmt
- (@SBadCharacterRadix2, [s]);
- end;
- // TODO Parse 64 bits at a time
- b := b.ShiftLeft(1);
- end;
- 8:
- begin
- // TODO Need this because we are parsing in radix 10 above
- if (i >= 8) then
- begin
- raise EFormatCryptoLibException.CreateResFmt
- (@SBadCharacterRadix8, [s]);
- end;
- // TODO Parse 63 bits at a time
- b := b.ShiftLeft(3);
- end;
- 16:
- begin
- b := b.ShiftLeft(64);
- end
- else
- begin
- b := b.Multiply(rE);
- end;
- end;
- b := b.Add(bi);
- index := Next;
- Next := Next + chunk;
- end;
- if (index < System.length(str) + 1) then
- begin
- s := System.Copy(str, index, System.length(str) - (index - 1));
- if (style = TNumberStyles.AllowHexSpecifier) then
- begin
- temp := '$' + s;
- end
- else
- begin
- temp := s;
- end;
- {$IFDEF FPC}
- i := StrToQWord(temp);
- {$ELSE}
- i := StrToUInt64(temp);
- {$ENDIF FPC}
- bi := CreateUValueOf(i);
- if (b.Fsign > 0) then
- begin
- if (radix = 2) then
- begin
- // NB: Can't reach here since we are parsing one char at a time
- {$IFDEF DEBUG}
- System.Assert(false);
- {$ENDIF DEBUG}
- // TODO Parse all bits at once
- // b = b.ShiftLeft(s.Length);
- end
- else if (radix = 8) then
- begin
- // NB: Can't reach here since we are parsing one char at a time
- {$IFDEF DEBUG}
- System.Assert(false);
- {$ENDIF DEBUG}
- // TODO Parse all bits at once
- // b = b.ShiftLeft(s.Length * 3);
- end
- else if (radix = 16) then
- begin
- b := b.ShiftLeft(System.length(s) shl 2);
- end
- else
- begin
- b := b.Multiply(r.Pow(System.length(s)));
- end;
- b := b.Add(bi);
- end
- else
- begin
- b := bi;
- end;
- end;
- Fmagnitude := b.Fmagnitude;
- end;
- function TBigInteger.Pow(exp: Int32): TBigInteger;
- var
- powOf2: Int64;
- y, z: TBigInteger;
- begin
- if (exp <= 0) then
- begin
- if (exp < 0) then
- begin
- raise EArithmeticCryptoLibException.CreateRes(@SNegativeExponent);
- end;
- Result := One;
- Exit;
- end;
- if (Fsign = 0) then
- begin
- Result := Self;
- Exit;
- end;
- if (QuickPow2Check()) then
- begin
- powOf2 := Int64(exp) * (Int64(BitLength) - 1);
- if (powOf2 > System.High(Int32)) then
- begin
- raise EArithmeticCryptoLibException.CreateRes(@SResultTooLarge);
- end;
- Result := One.ShiftLeft(Int32(powOf2));
- Exit;
- end;
- y := One;
- z := Self;
- while True do
- begin
- if ((exp and $1) = 1) then
- begin
- y := y.Multiply(z);
- end;
- exp := exp shr 1;
- if (exp = 0) then
- begin
- break;
- end;
- z := z.Multiply(z);
- end;
- Result := y;
- end;
- function TBigInteger.DivideWords(w: Int32): TBigInteger;
- var
- n: Int32;
- mag: TCryptoLibInt32Array;
- begin
- {$IFDEF DEBUG}
- System.Assert(w >= 0);
- {$ENDIF DEBUG}
- n := System.length(Fmagnitude);
- if (w >= n) then
- begin
- Result := Zero;
- Exit;
- end;
- System.SetLength(mag, n - w);
- System.Move(Fmagnitude[0], mag[0], (n - w) * System.SizeOf(Int32));
- Result := TBigInteger.Create(Fsign, mag, false);
- end;
- function TBigInteger.RemainderWords(w: Int32): TBigInteger;
- var
- n: Int32;
- mag: TCryptoLibInt32Array;
- begin
- {$IFDEF DEBUG}
- System.Assert(w >= 0);
- {$ENDIF DEBUG}
- n := System.length(Fmagnitude);
- if (w >= n) then
- begin
- Result := Self;
- Exit;
- end;
- System.SetLength(mag, w);
- System.Move(Fmagnitude[n - w], mag[0], w * System.SizeOf(Int32));
- Result := TBigInteger.Create(Fsign, mag, false);
- end;
- class function TBigInteger.ProbablePrime(BitLength: Int32;
- const random: IRandom): TBigInteger;
- begin
- Result := TBigInteger.Create(BitLength, 100, random);
- end;
- function TBigInteger.RabinMillerTest(certainty: Int32; const random: IRandom;
- randomlySelected: Boolean): Boolean;
- var
- bits, iterations, itersFor100Cert, s, j, shiftval: Int32;
- n, r, montRadix, minusMontRadix, a, y: TBigInteger;
- begin
- bits := BitLength;
- {$IFDEF DEBUG}
- System.Assert(certainty > 0);
- System.Assert(bits > 2);
- System.Assert(TestBit(0));
- {$ENDIF DEBUG}
- iterations := ((certainty - 1) shr 1) + 1;
- if (randomlySelected) then
- begin
- if bits >= 1024 then
- begin
- itersFor100Cert := 4
- end
- else if bits >= 512 then
- begin
- itersFor100Cert := 8
- end
- else if bits >= 256 then
- begin
- itersFor100Cert := 16
- end
- else
- begin
- itersFor100Cert := 50
- end;
- if (certainty < 100) then
- begin
- iterations := Math.Min(itersFor100Cert, iterations);
- end
- else
- begin
- iterations := iterations - 50;
- iterations := iterations + itersFor100Cert;
- end;
- end;
- // let n = 1 + d . 2^s
- n := Self;
- shiftval := Int32(-1) shl 1; // -2
- s := n.GetLowestSetBitMaskFirst(shiftval);
- {$IFDEF DEBUG}
- System.Assert(s >= 1);
- {$ENDIF DEBUG}
- r := n.ShiftRight(s);
- // NOTE: Avoid conversion to/from Montgomery form and check for R/-R as result instead
- montRadix := One.ShiftLeft(32 * System.length(n.Fmagnitude)).Remainder(n);
- minusMontRadix := n.Subtract(montRadix);
- repeat
- repeat
- a := TBigInteger.Create(n.BitLength, random);
- until (not((a.Fsign = 0) or (a.CompareTo(n) >= 0) or
- (a.IsEqualMagnitude(montRadix)) or (a.IsEqualMagnitude(minusMontRadix))));
- y := ModPowMonty(a, r, n, false);
- if (not y.Equals(montRadix)) then
- begin
- j := 0;
- while (not y.Equals(minusMontRadix)) do
- begin
- System.Inc(j);
- if (j = s) then
- begin
- Result := false;
- Exit;
- end;
- y := ModPowMonty(y, Two, n, false);
- if (y.Equals(montRadix)) then
- begin
- Result := false;
- Exit;
- end;
- end;
- end;
- System.Dec(iterations);
- until (not(iterations > 0));
- Result := True;
- end;
- function TBigInteger.RabinMillerTest(certainty: Int32;
- const random: IRandom): Boolean;
- begin
- Result := RabinMillerTest(certainty, random, false);
- end;
- class function TBigInteger.ReduceBarrett(x: TBigInteger;
- const m, mr, yu: TBigInteger): TBigInteger;
- var
- xLen, mLen, k: Int32;
- q1, q2, q3, r1, r2, r3: TBigInteger;
- begin
- xLen := x.BitLength;
- mLen := m.BitLength;
- if (xLen < mLen) then
- begin
- Result := x;
- Exit;
- end;
- if ((xLen - mLen) > 1) then
- begin
- k := System.length(m.Fmagnitude);
- q1 := x.DivideWords(k - 1);
- q2 := q1.Multiply(yu); // TODO Only need partial multiplication here
- q3 := q2.DivideWords(k + 1);
- r1 := x.RemainderWords(k + 1);
- r2 := q3.Multiply(m); // TODO Only need partial multiplication here
- r3 := r2.RemainderWords(k + 1);
- x := r1.Subtract(r3);
- if (x.Fsign < 0) then
- begin
- x := x.Add(mr);
- end;
- end;
- while (x.CompareTo(m) >= 0) do
- begin
- x := x.Subtract(m);
- end;
- Result := x;
- end;
- function TBigInteger.Remainder(x, y: TCryptoLibInt32Array)
- : TCryptoLibInt32Array;
- var
- xStart, yStart, xyCmp, yBitLength, xBitLength, shift, cBitLength, cStart,
- len: Int32;
- c: TCryptoLibInt32Array;
- firstC, firstX: UInt32;
- begin
- xStart := 0;
- while ((xStart < System.length(x)) and (x[xStart] = 0)) do
- begin
- System.Inc(xStart);
- end;
- yStart := 0;
- while ((yStart < System.length(y)) and (y[yStart] = 0)) do
- begin
- System.Inc(yStart);
- end;
- {$IFDEF DEBUG}
- System.Assert(yStart < System.length(y));
- {$ENDIF DEBUG}
- xyCmp := CompareNoLeadingZeroes(xStart, x, yStart, y);
- if (xyCmp > 0) then
- begin
- yBitLength := CalcBitLength(1, yStart, y);
- xBitLength := CalcBitLength(1, xStart, x);
- shift := xBitLength - yBitLength;
- cStart := 0;
- cBitLength := yBitLength;
- if (shift > 0) then
- begin
- c := ShiftLeft(y, shift);
- cBitLength := cBitLength + shift;
- {$IFDEF DEBUG}
- System.Assert(c[0] <> 0);
- {$ENDIF DEBUG}
- end
- else
- begin
- len := System.length(y) - yStart;
- System.SetLength(c, len);
- System.Move(y[yStart], c[0], len * System.SizeOf(Int32));
- end;
- while True do
- begin
- if ((cBitLength < xBitLength) or (CompareNoLeadingZeroes(xStart, x,
- cStart, c) >= 0)) then
- begin
- Subtract(xStart, x, cStart, c);
- while (x[xStart] = 0) do
- begin
- System.Inc(xStart);
- if (xStart = System.length(x)) then
- begin
- Result := x;
- Exit;
- end;
- end;
- // xBitLength = CalcBitLength(xStart, x);
- xBitLength := 32 * (System.length(x) - xStart - 1) + BitLen(x[xStart]);
- if (xBitLength <= yBitLength) then
- begin
- if (xBitLength < yBitLength) then
- begin
- Result := x;
- Exit;
- end;
- xyCmp := CompareNoLeadingZeroes(xStart, x, yStart, y);
- if (xyCmp <= 0) then
- begin
- break;
- end;
- end;
- end;
- shift := cBitLength - xBitLength;
- // NB: The case where c[cStart] is 1-bit is harmless
- if (shift = 1) then
- begin
- firstC := UInt32(c[cStart] shr 1);
- firstX := UInt32(x[xStart]);
- if (firstC > firstX) then
- begin
- System.Inc(shift);
- end;
- end;
- if (shift < 2) then
- begin
- ShiftRightOneInPlace(cStart, c);
- System.Dec(cBitLength);
- end
- else
- begin
- ShiftRightInPlace(cStart, c, shift);
- cBitLength := cBitLength - shift;
- end;
- // cStart = c.Length - ((cBitLength + 31) / 32);
- while (c[cStart] = 0) do
- begin
- System.Inc(cStart);
- end;
- end;
- end;
- if (xyCmp = 0) then
- begin
- System.FillChar(x[xStart], (System.length(x) - xStart) *
- System.SizeOf(Int32), Int32(0));
- end;
- Result := x;
- end;
- function TBigInteger.SetBit(n: Int32): TBigInteger;
- begin
- if (n < 0) then
- begin
- raise EArithmeticCryptoLibException.CreateRes(@SInvalidBitAddress);
- end;
- if (TestBit(n)) then
- begin
- Result := Self;
- Exit;
- end;
- // TODO Handle negative values and zero
- if ((Fsign > 0) and (n < (BitLength - 1))) then
- begin
- Result := FlipExistingBit(n);
- Exit;
- end;
- Result := &Or(One.ShiftLeft(n));
- end;
- function TBigInteger.ShiftLeft(n: Int32): TBigInteger;
- begin
- if ((Fsign = 0) or (System.length(Fmagnitude) = 0)) then
- begin
- Result := Zero;
- Exit;
- end;
- if (n = 0) then
- begin
- Result := Self;
- Exit;
- end;
- if (n < 0) then
- begin
- Result := ShiftRight(-n);
- Exit;
- end;
- Result := TBigInteger.Create(Fsign, ShiftLeft(Fmagnitude, n), True);
- // if (FnBits <> -1) then
- if (BitCount <> -1) then
- begin
- if Fsign > 0 then
- begin
- Result.FnBits := FnBits;
- end
- else
- begin
- Result.FnBits := FnBits + n;
- end;
- end;
- if (FnBitLength <> -1) then
- begin
- Result.FnBitLength := FnBitLength + n;
- end;
- end;
- class function TBigInteger.ShiftLeft(mag: TCryptoLibInt32Array; n: Int32)
- : TCryptoLibInt32Array;
- var
- nInts, nBits, magLen, i, nBits2, highBits, m, j, Next: Int32;
- newMag: TCryptoLibInt32Array;
- begin
- nInts := Int32(UInt32(n) shr 5);
- nBits := n and $1F;
- magLen := System.length(mag);
- if (nBits = 0) then
- begin
- System.SetLength(newMag, magLen + nInts);
- System.Move(mag[0], newMag[0], System.length(mag) * System.SizeOf(Int32));
- end
- else
- begin
- i := 0;
- nBits2 := 32 - nBits;
- highBits := Int32(UInt32(mag[0]) shr nBits2);
- if (highBits <> 0) then
- begin
- System.SetLength(newMag, magLen + nInts + 1);
- newMag[i] := highBits;
- System.Inc(i);
- end
- else
- begin
- System.SetLength(newMag, magLen + nInts);
- end;
- m := mag[0];
- j := 0;
- while (j < (magLen - 1)) do
- begin
- Next := mag[j + 1];
- newMag[i] := (m shl nBits) or Int32(UInt32(Next) shr nBits2);
- System.Inc(i);
- m := Next;
- System.Inc(j);
- end;
- newMag[i] := mag[magLen - 1] shl nBits;
- end;
- Result := newMag;
- end;
- function TBigInteger.ShiftRight(n: Int32): TBigInteger;
- var
- resultLength, numInts, numBits, numBits2, magPos, i: Int32;
- res: TCryptoLibInt32Array;
- begin
- if (n = 0) then
- begin
- Result := Self;
- Exit;
- end;
- if (n < 0) then
- begin
- Result := ShiftLeft(-n);
- Exit;
- end;
- if (n >= BitLength) then
- begin
- if Fsign < 0 then
- begin
- Result := One.Negate();
- Exit;
- end
- else
- begin
- Result := Zero;
- Exit;
- end;
- end;
- // int[] res = (int[]) this.magnitude.Clone();
- //
- // ShiftRightInPlace(0, res, n);
- //
- // return new BigInteger(this.sign, res, true);
- resultLength := (BitLength - n + 31) shr 5;
- System.SetLength(res, resultLength);
- numInts := n shr 5;
- numBits := n and 31;
- if (numBits = 0) then
- begin
- System.Move(Fmagnitude[0], res[0], System.length(res) *
- System.SizeOf(Int32));
- end
- else
- begin
- numBits2 := 32 - numBits;
- magPos := System.length(Fmagnitude) - 1 - numInts;
- i := resultLength - 1;
- while i >= 0 do
- begin
- res[i] := Int32(UInt32(Fmagnitude[magPos]) shr numBits);
- System.Dec(magPos);
- if (magPos >= 0) then
- begin
- res[i] := res[i] or (Fmagnitude[magPos] shl numBits2);
- end;
- System.Dec(i);
- end;
- end;
- {$IFDEF DEBUG}
- System.Assert(res[0] <> 0);
- {$ENDIF DEBUG}
- Result := TBigInteger.Create(Fsign, res, false);
- end;
- class procedure TBigInteger.ShiftRightInPlace(start: Int32;
- mag: TCryptoLibInt32Array; n: Int32);
- var
- nInts, nBits, magEnd, delta, i, nBits2, m, Next: Int32;
- begin
- nInts := Int32(UInt32(n) shr 5) + start;
- nBits := n and $1F;
- magEnd := System.length(mag) - 1;
- if (nInts <> start) then
- begin
- delta := (nInts - start);
- i := magEnd;
- while i >= nInts do
- begin
- mag[i] := mag[i - delta];
- System.Dec(i);
- end;
- i := nInts - 1;
- while i >= start do
- begin
- mag[i] := 0;
- System.Dec(i);
- end;
- end;
- if (nBits <> 0) then
- begin
- nBits2 := 32 - nBits;
- m := mag[magEnd];
- i := magEnd;
- while i > nInts do
- begin
- Next := mag[i - 1];
- mag[i] := Int32(UInt32(m) shr nBits) or (Next shl nBits2);
- m := Next;
- System.Dec(i);
- end;
- mag[nInts] := Int32(UInt32(mag[nInts]) shr nBits);
- end;
- end;
- class procedure TBigInteger.ShiftRightOneInPlace(start: Int32;
- mag: TCryptoLibInt32Array);
- var
- i, m, Next: Int32;
- begin
- i := System.length(mag);
- m := mag[i - 1];
- System.Dec(i);
- while (i > start) do
- begin
- Next := mag[i - 1];
- mag[i] := (Int32(UInt32(m) shr 1)) or (Next shl 31);
- m := Next;
- System.Dec(i);
- end;
- mag[start] := Int32(UInt32(mag[start]) shr 1);
- end;
- class function TBigInteger.Square(w, x: TCryptoLibInt32Array)
- : TCryptoLibInt32Array;
- var
- c, v, prod: UInt64;
- wBase, i, j: Int32;
- begin
- // Note: this method allows w to be only (2 * x.Length - 1) words if result will fit
- // if (w.Length != 2 * x.Length)
- // throw new ArgumentException("no I don't think so...");
- wBase := System.length(w) - 1;
- i := System.length(x) - 1;
- while i > 0 do
- begin
- v := UInt32(x[i]);
- c := v * v + UInt32(w[wBase]);
- w[wBase] := Int32(c);
- c := c shr 32;
- j := i - 1;
- while j >= 0 do
- begin
- prod := v * UInt32(x[j]);
- System.Dec(wBase);
- c := c + ((UInt32(w[wBase]) and UIMASK) + (UInt32(prod) shl 1));
- w[wBase] := Int32(c);
- c := (c shr 32) + (prod shr 31);
- System.Dec(j);
- end;
- System.Dec(wBase);
- c := c + UInt32(w[wBase]);
- w[wBase] := Int32(c);
- System.Dec(wBase);
- if (wBase >= 0) then
- begin
- w[wBase] := Int32(c shr 32);
- end
- else
- begin
- {$IFDEF DEBUG}
- System.Assert((c shr 32) = 0);
- {$ENDIF DEBUG}
- end;
- wBase := wBase + i;
- System.Dec(i);
- end;
- c := UInt32(x[0]);
- c := (c * c) + UInt32(w[wBase]);
- w[wBase] := Int32(c);
- System.Dec(wBase);
- if (wBase >= 0) then
- begin
- w[wBase] := w[wBase] + Int32(c shr 32);
- end
- else
- begin
- {$IFDEF DEBUG}
- System.Assert((c shr 32) = 0);
- {$ENDIF DEBUG}
- end;
- Result := w;
- end;
- class procedure TBigInteger.SquareMonty(a, x, m: TCryptoLibInt32Array;
- mDash: UInt32; smallMontyModulus: Boolean);
- var
- n, aMax, j, i: Int32;
- xVal, a0: UInt32;
- x0, carry, t, prod1, prod2, xi: UInt64;
- begin
- // mDash = -m^(-1) mod b
- n := System.length(m);
- if (n = 1) then
- begin
- xVal := UInt32(x[0]);
- x[0] := Int32(MultiplyMontyNIsOne(xVal, xVal, UInt32(m[0]), mDash));
- Exit;
- end;
- x0 := UInt32(x[n - 1]);
- carry := x0 * x0;
- t := UInt32(UInt64(UInt32(carry)) * mDash);
- prod2 := t * UInt32(m[n - 1]);
- carry := carry + UInt32(prod2);
- {$IFDEF DEBUG}
- System.Assert(UInt32(carry) = 0);
- {$ENDIF DEBUG}
- carry := (carry shr 32) + (prod2 shr 32);
- j := n - 2;
- while j >= 0 do
- begin
- prod1 := x0 * UInt32(x[j]);
- prod2 := t * UInt32(m[j]);
- carry := carry + ((prod2 and UIMASK) + (UInt32(prod1) shl 1));
- a[j + 2] := Int32(carry);
- carry := (carry shr 32) + (prod1 shr 31) + (prod2 shr 32);
- System.Dec(j);
- end;
- a[1] := Int32(carry);
- aMax := Int32(carry shr 32);
- i := n - 2;
- while i >= 0 do
- begin
- a0 := UInt32(a[n]);
- t := UInt32(UInt64(a0) * mDash);
- carry := t * UInt32(m[n - 1]) + a0;
- {$IFDEF DEBUG}
- System.Assert(UInt32(carry) = 0);
- {$ENDIF DEBUG}
- carry := carry shr 32;
- j := n - 2;
- while j > i do
- begin
- carry := carry + (t * UInt32(m[j]) + UInt32(a[j + 1]));
- a[j + 2] := Int32(carry);
- carry := carry shr 32;
- System.Dec(j);
- end;
- xi := UInt32(x[i]);
- prod1 := xi * xi;
- prod2 := t * UInt32(m[i]);
- carry := carry + ((prod1 and UIMASK) + UInt32(prod2) + UInt32(a[i + 1]));
- a[i + 2] := Int32(carry);
- carry := (carry shr 32) + (prod1 shr 32) + (prod2 shr 32);
- j := i - 1;
- while j >= 0 do
- begin
- prod1 := xi * UInt32(x[j]);
- prod2 := t * UInt32(m[j]);
- carry := carry + ((prod2 and UIMASK) + (UInt32(prod1) shl 1) +
- UInt32(a[j + 1]));
- a[j + 2] := Int32(carry);
- carry := (carry shr 32) + (prod1 shr 31) + (prod2 shr 32);
- System.Dec(j);
- end;
- carry := carry + UInt32(aMax);
- a[1] := Int32(carry);
- aMax := Int32(carry shr 32);
- System.Dec(i);
- end;
- a[0] := aMax;
- if ((not smallMontyModulus) and (CompareTo(0, a, 0, m) >= 0)) then
- begin
- Subtract(0, a, 0, m);
- end;
- System.Move(a[1], x[0], n * System.SizeOf(Int32));
- end;
- function TBigInteger.Subtract(const n: TBigInteger): TBigInteger;
- var
- compare: Int32;
- bigun, lilun: TBigInteger;
- begin
- if (n.Fsign = 0) then
- begin
- Result := Self;
- Exit;
- end;
- if (Fsign = 0) then
- begin
- Result := n.Negate();
- Exit;
- end;
- if (Fsign <> n.Fsign) then
- begin
- Result := Add(n.Negate());
- Exit;
- end;
- compare := CompareNoLeadingZeroes(0, Fmagnitude, 0, n.Fmagnitude);
- if (compare = 0) then
- begin
- Result := Zero;
- Exit;
- end;
- if (compare < 0) then
- begin
- bigun := n;
- lilun := Self;
- end
- else
- begin
- bigun := Self;
- lilun := n;
- end;
- Result := TBigInteger.Create(Fsign * compare, doSubBigLil(bigun.Fmagnitude,
- lilun.Fmagnitude), True);
- end;
- function TBigInteger.ToString(radix: Int32): String;
- var
- firstNonZero, pos, mask, bits, i, scale: Int32;
- sl: TStringList;
- s: TList<String>;
- moduli: TList<TBigInteger>;
- u, q, r: TBigInteger;
- begin
- // TODO Make this method work for other radices (ideally 2 <= radix <= 36 as in Java)
- case (radix) of
- 2, 8, 10, 16:
- begin
- // do nothing because it is in valid supported range
- end
- else
- begin
- raise EFormatCryptoLibException.CreateRes(@SUnSupportedBase);
- end;
- end;
- // NB: Can only happen to internally managed instances
- if ((not FIsInitialized) and (Fmagnitude = Nil)) then
- begin
- Result := 'Nil';
- Exit;
- end;
- if (Fsign = 0) then
- begin
- Result := '0';
- Exit;
- end;
- // NOTE: This *should* be unnecessary, since the magnitude *should* never have leading zero digits
- firstNonZero := 0;
- while (firstNonZero < System.length(Fmagnitude)) do
- begin
- if (Fmagnitude[firstNonZero] <> 0) then
- begin
- break;
- end;
- System.Inc(firstNonZero);
- end;
- if (firstNonZero = System.length(Fmagnitude)) then
- begin
- Result := '0';
- Exit;
- end;
- sl := TStringList.Create();
- sl.LineBreak := '';
- try
- if (Fsign = -1) then
- begin
- sl.Add('-');
- end;
- case radix of
- 2:
- begin
- pos := firstNonZero;
- sl.Add(TBigInteger.IntToBin(Fmagnitude[pos]));
- System.Inc(pos);
- while (pos < System.length(Fmagnitude)) do
- begin
- AppendZeroExtendedString(sl,
- TBigInteger.IntToBin(Fmagnitude[pos]), 32);
- System.Inc(pos);
- end;
- end;
- 8:
- begin
- mask := (1 shl 30) - 1;
- u := Abs();
- bits := u.BitLength;
- s := TList<string>.Create();
- try
- while (bits > 30) do
- begin
- s.Add(TBigInteger.IntToOctal(u.Int32Value and mask));
- u := u.ShiftRight(30);
- bits := bits - 30;
- end;
- sl.Add(TBigInteger.IntToOctal(u.Int32Value));
- i := s.Count - 1;
- while i >= 0 do
- begin
- AppendZeroExtendedString(sl, s[i], 10);
- System.Dec(i);
- end;
- finally
- s.Free;
- end;
- end;
- 16:
- begin
- pos := firstNonZero;
- sl.Add(IntToHex(Fmagnitude[pos], 2));
- System.Inc(pos);
- while (pos < System.length(Fmagnitude)) do
- begin
- AppendZeroExtendedString(sl, IntToHex(Fmagnitude[pos], 2), 8);
- System.Inc(pos);
- end;
- end;
- // TODO This could work for other radices if there is an alternative to Convert.ToString method
- // default:
- 10:
- begin
- q := Abs();
- if (q.BitLength < 64) then
- begin
- sl.Add(IntToStr(q.Int64Value));
- Result := sl.Text;
- Exit;
- end;
- // TODO Could cache the moduli for each radix (soft reference?)
- moduli := TList<TBigInteger>.Create();
- try
- r := TBigInteger.ValueOf(radix);
- while (r.CompareTo(q) <= 0) do
- begin
- moduli.Add(r);
- r := r.Square();
- end;
- scale := moduli.Count;
- sl.Capacity := sl.Capacity + (1 shl scale);
- ToString(sl, radix, moduli, scale, q);
- finally
- moduli.Free;
- end;
- end;
- end;
- Result := LowerCase(sl.Text);
- finally
- sl.Free;
- end;
- end;
- function TBigInteger.ToString: String;
- begin
- Result := ToString(10);
- end;
- class function TBigInteger.GetWindowList(mag: TCryptoLibInt32Array;
- extraBits: Int32): TCryptoLibInt32Array;
- var
- i, v, leadingBits, resultSize, resultPos, bitPos, mult, multLimit,
- zeroes: Int32;
- begin
- v := mag[0];
- {$IFDEF DEBUG}
- System.Assert(v <> 0);
- {$ENDIF DEBUG}
- leadingBits := BitLen(v);
- resultSize := (((System.length(mag) - 1) shl 5) + leadingBits)
- div (1 + extraBits) + 2;
- System.SetLength(Result, resultSize);
- resultPos := 0;
- bitPos := 33 - leadingBits;
- v := v shl bitPos;
- mult := 1;
- multLimit := 1 shl extraBits;
- zeroes := 0;
- i := 0;
- while True do
- begin
- while bitPos < 32 do
- begin
- if (mult < multLimit) then
- begin
- mult := (mult shl 1) or Int32((UInt32(v) shr 31));
- end
- else if (v < 0) then
- begin
- Result[resultPos] := CreateWindowEntry(mult, zeroes);
- System.Inc(resultPos);
- mult := 1;
- zeroes := 0;
- end
- else
- begin
- System.Inc(zeroes);
- end;
- v := v shl 1;
- System.Inc(bitPos);
- end;
- System.Inc(i);
- if (i = System.length(mag)) then
- begin
- Result[resultPos] := CreateWindowEntry(mult, zeroes);
- System.Inc(resultPos);
- break;
- end;
- v := mag[i];
- bitPos := 0;
- end;
- Result[resultPos] := -1;
- end;
- function TBigInteger.CheckProbablePrime(certainty: Int32; const random: IRandom;
- randomlySelected: Boolean): Boolean;
- var
- numLists, i, j, prime, qRem, test: Int32;
- primeList: TCryptoLibInt32Array;
- begin
- {$IFDEF DEBUG}
- System.Assert(certainty > 0);
- System.Assert(CompareTo(Two) > 0);
- System.Assert(TestBit(0));
- {$ENDIF DEBUG}
- // Try to reduce the penalty for really small numbers
- numLists := Math.Min(BitLength - 1, System.length(primeLists));
- for i := 0 to System.Pred(numLists) do
- begin
- test := Remainder(primeProducts[i]);
- primeList := primeLists[i];
- for j := 0 to System.Pred(System.length(primeList)) do
- begin
- prime := primeList[j];
- qRem := test mod prime;
- if (qRem = 0) then
- begin
- // We may find small numbers in the list
- Result := (BitLength < 16) and (Int32Value = prime);
- Exit;
- end;
- end;
- end;
- // TODO Special case for < 10^16 (RabinMiller fixed list)
- // if (BitLength < 30)
- // {
- // RabinMiller against 2, 3, 5, 7, 11, 13, 23 is sufficient
- // }
- // TODO Is it worth trying to create a hybrid of these two?
- Result := RabinMillerTest(certainty, random, randomlySelected);
- // return SolovayStrassenTest(certainty, random);
- // bool rbTest = RabinMillerTest(certainty, random);
- // bool ssTest = SolovayStrassenTest(certainty, random);
- //
- // Debug.Assert(rbTest == ssTest);
- //
- // return rbTest;
- end;
- function TBigInteger.ClearBit(n: Int32): TBigInteger;
- begin
- if (n < 0) then
- begin
- raise EArithmeticCryptoLibException.CreateRes(@SInvalidBitAddress);
- end;
- if (not TestBit(n)) then
- begin
- Result := Self;
- Exit;
- end;
- // TODO Handle negative values
- if ((Fsign > 0) and (n < (BitLength - 1))) then
- begin
- Result := FlipExistingBit(n);
- Exit;
- end;
- Result := AndNot(One.ShiftLeft(n));
- end;
- class function TBigInteger.CompareNoLeadingZeroes(xIndx: Int32;
- x: TCryptoLibInt32Array; yIndx: Int32; y: TCryptoLibInt32Array): Int32;
- var
- diff: Int32;
- v1, v2: UInt32;
- begin
- diff := (System.length(x) - System.length(y)) - (xIndx - yIndx);
- if (diff <> 0) then
- begin
- if diff < 0 then
- begin
- Result := -1;
- Exit;
- end
- else
- begin
- Result := 1;
- Exit;
- end;
- end;
- // lengths of magnitudes the same, test the magnitude values
- while (xIndx < System.length(x)) do
- begin
- v1 := UInt32(x[xIndx]);
- System.Inc(xIndx);
- v2 := UInt32(y[yIndx]);
- System.Inc(yIndx);
- if (v1 <> v2) then
- begin
- if v1 < v2 then
- begin
- Result := -1;
- Exit;
- end
- else
- begin
- Result := 1;
- Exit;
- end;
- end;
- end;
- Result := 0;
- end;
- class function TBigInteger.CompareTo(xIndx: Int32; x: TCryptoLibInt32Array;
- yIndx: Int32; y: TCryptoLibInt32Array): Int32;
- begin
- while ((xIndx <> System.length(x)) and (x[xIndx] = 0)) do
- begin
- System.Inc(xIndx);
- end;
- while ((yIndx <> System.length(y)) and (y[yIndx] = 0)) do
- begin
- System.Inc(yIndx);
- end;
- Result := CompareNoLeadingZeroes(xIndx, x, yIndx, y);
- end;
- function TBigInteger.Divide(x, y: TCryptoLibInt32Array): TCryptoLibInt32Array;
- var
- xStart, yStart, xyCmp, yBitLength, xBitLength, shift, iCountStart, cBitLength,
- cStart, len: Int32;
- Count, iCount, c: TCryptoLibInt32Array;
- firstC, firstX: UInt32;
- begin
- xStart := 0;
- while ((xStart < System.length(x)) and (x[xStart] = 0)) do
- begin
- System.Inc(xStart);
- end;
- yStart := 0;
- while ((yStart < System.length(y)) and (y[yStart] = 0)) do
- begin
- System.Inc(yStart);
- end;
- {$IFDEF DEBUG}
- System.Assert(yStart < System.length(y));
- {$ENDIF DEBUG}
- xyCmp := CompareNoLeadingZeroes(xStart, x, yStart, y);
- if (xyCmp > 0) then
- begin
- yBitLength := CalcBitLength(1, yStart, y);
- xBitLength := CalcBitLength(1, xStart, x);
- shift := xBitLength - yBitLength;
- iCountStart := 0;
- cStart := 0;
- cBitLength := yBitLength;
- if (shift > 0) then
- begin
- // iCount = ShiftLeft(One.magnitude, shift);
- System.SetLength(iCount, (shift shr 5) + 1);
- iCount[0] := 1 shl (shift and 31);
- c := ShiftLeft(y, shift);
- cBitLength := cBitLength + shift;
- end
- else
- begin
- iCount := TCryptoLibInt32Array.Create(1);
- len := System.length(y) - yStart;
- System.SetLength(c, len);
- System.Move(y[yStart], c[0], len * System.SizeOf(Int32));
- end;
- System.SetLength(Count, System.length(iCount));
- while True do
- begin
- if ((cBitLength < xBitLength) or (CompareNoLeadingZeroes(xStart, x,
- cStart, c) >= 0)) then
- begin
- Subtract(xStart, x, cStart, c);
- AddMagnitudes(Count, iCount);
- while (x[xStart] = 0) do
- begin
- System.Inc(xStart);
- if (xStart = System.length(x)) then
- begin
- Result := Count;
- Exit;
- end;
- end;
- // xBitLength = CalcBitLength(xStart, x);
- xBitLength := 32 * (System.length(x) - xStart - 1) + BitLen(x[xStart]);
- if (xBitLength <= yBitLength) then
- begin
- if (xBitLength < yBitLength) then
- begin
- Result := Count;
- Exit;
- end;
- xyCmp := CompareNoLeadingZeroes(xStart, x, yStart, y);
- if (xyCmp <= 0) then
- begin
- break;
- end;
- end;
- end;
- shift := cBitLength - xBitLength;
- // NB: The case where c[cStart] is 1-bit is harmless
- if (shift = 1) then
- begin
- firstC := UInt32(c[cStart] shr 1);
- firstX := UInt32(x[xStart]);
- if (firstC > firstX) then
- begin
- System.Inc(shift);
- end;
- end;
- if (shift < 2) then
- begin
- ShiftRightOneInPlace(cStart, c);
- System.Dec(cBitLength);
- ShiftRightOneInPlace(iCountStart, iCount);
- end
- else
- begin
- ShiftRightInPlace(cStart, c, shift);
- cBitLength := cBitLength - shift;
- ShiftRightInPlace(iCountStart, iCount, shift);
- end;
- // cStart = c.Length - ((cBitLength + 31) / 32);
- while (c[cStart] = 0) do
- begin
- System.Inc(cStart);
- end;
- while (iCount[iCountStart] = 0) do
- begin
- System.Inc(iCountStart);
- end;
- end;
- end
- else
- begin
- System.SetLength(Count, 1);
- end;
- if (xyCmp = 0) then
- begin
- AddMagnitudes(Count, One.Fmagnitude);
- System.FillChar(x[xStart], (System.length(x) - xStart) *
- System.SizeOf(Int32), Int32(0));
- end;
- Result := Count;
- end;
- function TBigInteger.Divide(const val: TBigInteger): TBigInteger;
- var
- tempRes: TBigInteger;
- mag: TCryptoLibInt32Array;
- begin
- if (val.Fsign = 0) then
- begin
- raise EArithmeticCryptoLibException.CreateRes(@SDivisionByZero);
- end;
- if (Fsign = 0) then
- begin
- Result := Zero;
- Exit;
- end;
- if (val.QuickPow2Check()) then // val is power of two
- begin
- tempRes := Abs().ShiftRight(val.Abs().BitLength - 1);
- if val.Fsign = Fsign then
- begin
- Result := tempRes;
- Exit;
- end
- else
- begin
- Result := tempRes.Negate();
- Exit;
- end;
- end;
- mag := System.Copy(Fmagnitude);
- Result := TBigInteger.Create(Fsign * val.Fsign,
- Divide(mag, val.Fmagnitude), True);
- end;
- function TBigInteger.DivideAndRemainder(const val: TBigInteger)
- : TCryptoLibGenericArray<TBigInteger>;
- var
- biggies: TCryptoLibGenericArray<TBigInteger>;
- e: Int32;
- Quotient: TBigInteger;
- Remainder, quotient_array: TCryptoLibInt32Array;
- begin
- if (val.Fsign = 0) then
- begin
- raise EArithmeticCryptoLibException.CreateRes(@SDivisionByZero);
- end;
- System.SetLength(biggies, 2);
- if (Fsign = 0) then
- begin
- biggies[0] := Zero;
- biggies[1] := Zero;
- end
- else if (val.QuickPow2Check()) then // val is power of two
- begin
- e := val.Abs().BitLength - 1;
- Quotient := Abs().ShiftRight(e);
- Remainder := LastNBits(e);
- if val.Fsign = Fsign then
- begin
- biggies[0] := Quotient
- end
- else
- begin
- biggies[0] := Quotient.Negate();
- end;
- biggies[1] := TBigInteger.Create(Fsign, Remainder, True);
- end
- else
- begin
- Remainder := System.Copy(Fmagnitude);
- quotient_array := Divide(Remainder, val.Fmagnitude);
- biggies[0] := TBigInteger.Create(Fsign * val.Fsign, quotient_array, True);
- biggies[1] := TBigInteger.Create(Fsign, Remainder, True);
- end;
- Result := biggies;
- end;
- function TBigInteger.ToByteArray(unsigned: Boolean): TCryptoLibByteArray;
- var
- nBits, nBytes, magIndex, bytesIndex: Int32;
- mag, lastMag: UInt32;
- bytes: TCryptoLibByteArray;
- carry: Boolean;
- begin
- if (Fsign = 0) then
- begin
- if unsigned then
- begin
- Result := FZeroEncoding;
- Exit;
- end
- else
- begin
- System.SetLength(Result, 1);
- Exit;
- end;
- end;
- if ((unsigned) and (Fsign > 0)) then
- begin
- nBits := BitLength;
- end
- else
- begin
- nBits := BitLength + 1;
- end;
- nBytes := GetByteLength(nBits);
- System.SetLength(bytes, nBytes);
- magIndex := System.length(Fmagnitude);
- bytesIndex := System.length(bytes);
- if (Fsign > 0) then
- begin
- while (magIndex > 1) do
- begin
- System.Dec(magIndex);
- mag := UInt32(Fmagnitude[magIndex]);
- System.Dec(bytesIndex);
- bytes[bytesIndex] := Byte(mag);
- System.Dec(bytesIndex);
- bytes[bytesIndex] := Byte(mag shr 8);
- System.Dec(bytesIndex);
- bytes[bytesIndex] := Byte(mag shr 16);
- System.Dec(bytesIndex);
- bytes[bytesIndex] := Byte(mag shr 24);
- end;
- lastMag := UInt32(Fmagnitude[0]);
- while (lastMag > System.High(Byte)) do
- begin
- System.Dec(bytesIndex);
- bytes[bytesIndex] := Byte(lastMag);
- lastMag := lastMag shr 8;
- end;
- System.Dec(bytesIndex);
- bytes[bytesIndex] := Byte(lastMag);
- end
- else // sign < 0
- begin
- carry := True;
- while (magIndex > 1) do
- begin
- System.Dec(magIndex);
- mag := not(UInt32(Fmagnitude[magIndex]));
- if (carry) then
- begin
- System.Inc(mag);
- carry := (mag = System.Low(UInt32));
- end;
- System.Dec(bytesIndex);
- bytes[bytesIndex] := Byte(mag);
- System.Dec(bytesIndex);
- bytes[bytesIndex] := Byte(mag shr 8);
- System.Dec(bytesIndex);
- bytes[bytesIndex] := Byte(mag shr 16);
- System.Dec(bytesIndex);
- bytes[bytesIndex] := Byte(mag shr 24);
- end;
- lastMag := UInt32(Fmagnitude[0]);
- if (carry) then
- begin
- // Never wraps because magnitude[0] != 0
- System.Dec(lastMag);
- end;
- while (lastMag > System.High(Byte)) do
- begin
- System.Dec(bytesIndex);
- bytes[bytesIndex] := Byte(not lastMag);
- lastMag := lastMag shr 8;
- end;
- System.Dec(bytesIndex);
- bytes[bytesIndex] := Byte(not lastMag);
- if (bytesIndex > 0) then
- begin
- System.Dec(bytesIndex);
- bytes[bytesIndex] := System.High(Byte);
- end;
- end;
- Result := bytes;
- end;
- function TBigInteger.ToByteArray: TCryptoLibByteArray;
- begin
- Result := ToByteArray(false);
- end;
- function TBigInteger.ToByteArrayUnsigned: TCryptoLibByteArray;
- begin
- Result := ToByteArray(True);
- end;
- end.
|