| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804 |
- #if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
- #pragma warning disable
- using System;
- using System.Collections.Generic;
- using System.Diagnostics;
- using System.Globalization;
- #if NETCOREAPP3_0_OR_GREATER
- using System.Numerics;
- #endif
- using System.Runtime.Serialization;
- using System.Text;
- using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Utilities;
- using BestHTTP.SecureProtocol.Org.BouncyCastle.Security;
- using BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities;
- namespace BestHTTP.SecureProtocol.Org.BouncyCastle.Math
- {
- [Serializable]
- public sealed class BigInteger
- : IComparable<BigInteger>, IEquatable<BigInteger>
- {
- // The first few odd primes
- /*
- 3 5 7 11 13 17 19 23 29
- 31 37 41 43 47 53 59 61 67 71
- 73 79 83 89 97 101 103 107 109 113
- 127 131 137 139 149 151 157 163 167 173
- 179 181 191 193 197 199 211 223 227 229
- 233 239 241 251 257 263 269 271 277 281
- 283 293 307 311 313 317 331 337 347 349
- 353 359 367 373 379 383 389 397 401 409
- 419 421 431 433 439 443 449 457 461 463
- 467 479 487 491 499 503 509 521 523 541
- 547 557 563 569 571 577 587 593 599 601
- 607 613 617 619 631 641 643 647 653 659
- 661 673 677 683 691 701 709 719 727 733
- 739 743 751 757 761 769 773 787 797 809
- 811 821 823 827 829 839 853 857 859 863
- 877 881 883 887 907 911 919 929 937 941
- 947 953 967 971 977 983 991 997 1009
- 1013 1019 1021 1031 1033 1039 1049 1051
- 1061 1063 1069 1087 1091 1093 1097 1103
- 1109 1117 1123 1129 1151 1153 1163 1171
- 1181 1187 1193 1201 1213 1217 1223 1229
- 1231 1237 1249 1259 1277 1279 1283 1289
- */
- // Each list has a product < 2^31
- internal static readonly int[][] primeLists = new int[][]
- {
- new int[]{ 3, 5, 7, 11, 13, 17, 19, 23 },
- new int[]{ 29, 31, 37, 41, 43 },
- new int[]{ 47, 53, 59, 61, 67 },
- new int[]{ 71, 73, 79, 83 },
- new int[]{ 89, 97, 101, 103 },
- new int[]{ 107, 109, 113, 127 },
- new int[]{ 131, 137, 139, 149 },
- new int[]{ 151, 157, 163, 167 },
- new int[]{ 173, 179, 181, 191 },
- new int[]{ 193, 197, 199, 211 },
- new int[]{ 223, 227, 229 },
- new int[]{ 233, 239, 241 },
- new int[]{ 251, 257, 263 },
- new int[]{ 269, 271, 277 },
- new int[]{ 281, 283, 293 },
- new int[]{ 307, 311, 313 },
- new int[]{ 317, 331, 337 },
- new int[]{ 347, 349, 353 },
- new int[]{ 359, 367, 373 },
- new int[]{ 379, 383, 389 },
- new int[]{ 397, 401, 409 },
- new int[]{ 419, 421, 431 },
- new int[]{ 433, 439, 443 },
- new int[]{ 449, 457, 461 },
- new int[]{ 463, 467, 479 },
- new int[]{ 487, 491, 499 },
- new int[]{ 503, 509, 521 },
- new int[]{ 523, 541, 547 },
- new int[]{ 557, 563, 569 },
- new int[]{ 571, 577, 587 },
- new int[]{ 593, 599, 601 },
- new int[]{ 607, 613, 617 },
- new int[]{ 619, 631, 641 },
- new int[]{ 643, 647, 653 },
- new int[]{ 659, 661, 673 },
- new int[]{ 677, 683, 691 },
- new int[]{ 701, 709, 719 },
- new int[]{ 727, 733, 739 },
- new int[]{ 743, 751, 757 },
- new int[]{ 761, 769, 773 },
- new int[]{ 787, 797, 809 },
- new int[]{ 811, 821, 823 },
- new int[]{ 827, 829, 839 },
- new int[]{ 853, 857, 859 },
- new int[]{ 863, 877, 881 },
- new int[]{ 883, 887, 907 },
- new int[]{ 911, 919, 929 },
- new int[]{ 937, 941, 947 },
- new int[]{ 953, 967, 971 },
- new int[]{ 977, 983, 991 },
- new int[]{ 997, 1009, 1013 },
- new int[]{ 1019, 1021, 1031 },
- new int[]{ 1033, 1039, 1049 },
- new int[]{ 1051, 1061, 1063 },
- new int[]{ 1069, 1087, 1091 },
- new int[]{ 1093, 1097, 1103 },
- new int[]{ 1109, 1117, 1123 },
- new int[]{ 1129, 1151, 1153 },
- new int[]{ 1163, 1171, 1181 },
- new int[]{ 1187, 1193, 1201 },
- new int[]{ 1213, 1217, 1223 },
- new int[]{ 1229, 1231, 1237 },
- new int[]{ 1249, 1259, 1277 },
- new int[]{ 1279, 1283, 1289 },
- };
- internal static readonly int[] primeProducts;
- private const long IMASK = 0xFFFFFFFFL;
- private const ulong UIMASK = 0xFFFFFFFFUL;
- private static readonly int[] ZeroMagnitude = new int[0];
- private static readonly byte[] ZeroEncoding = new byte[0];
- private static readonly BigInteger[] SMALL_CONSTANTS = new BigInteger[17];
- public static readonly BigInteger Zero;
- public static readonly BigInteger One;
- public static readonly BigInteger Two;
- public static readonly BigInteger Three;
- public static readonly BigInteger Four;
- public static readonly BigInteger Ten;
- #if !NETCOREAPP3_0_OR_GREATER
- private readonly static byte[] BitLengthTable =
- {
- 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
- };
- #endif
- // TODO Parse radix-2 64 bits at a time and radix-8 63 bits at a time
- private const int chunk2 = 1, chunk8 = 1, chunk10 = 19, chunk16 = 16;
- private static readonly BigInteger radix2, radix2E, radix8, radix8E, radix10, radix10E, radix16, radix16E;
- /*
- * These are the threshold bit-lengths (of an exponent) where we increase the window size.
- * They are calculated according to the expected savings in multiplications.
- * Some squares will also be saved on average, but we offset these against the extra storage costs.
- */
- private static readonly int[] ExpWindowThresholds = { 7, 25, 81, 241, 673, 1793, 4609, int.MaxValue };
- private const int BitsPerByte = 8;
- private const int BitsPerInt = 32;
- private const int BytesPerInt = 4;
- static BigInteger()
- {
- Zero = new BigInteger(0, ZeroMagnitude, false);
- Zero.nBits = 0; Zero.nBitLength = 0;
- SMALL_CONSTANTS[0] = Zero;
- for (uint i = 1; i < SMALL_CONSTANTS.Length; ++i)
- {
- SMALL_CONSTANTS[i] = CreateUValueOf(i);
- }
- One = SMALL_CONSTANTS[1];
- Two = SMALL_CONSTANTS[2];
- Three = SMALL_CONSTANTS[3];
- Four = SMALL_CONSTANTS[4];
- Ten = SMALL_CONSTANTS[10];
- radix2 = ValueOf(2);
- radix2E = radix2.Pow(chunk2);
- radix8 = ValueOf(8);
- radix8E = radix8.Pow(chunk8);
- radix10 = ValueOf(10);
- radix10E = radix10.Pow(chunk10);
- radix16 = ValueOf(16);
- radix16E = radix16.Pow(chunk16);
- primeProducts = new int[primeLists.Length];
- for (int i = 0; i < primeLists.Length; ++i)
- {
- int[] primeList = primeLists[i];
- int product = primeList[0];
- for (int j = 1; j < primeList.Length; ++j)
- {
- product *= primeList[j];
- }
- primeProducts[i] = product;
- }
- }
- private int[] magnitude; // array of ints with [0] being the most significant
- private int sign; // -1 means -ve; +1 means +ve; 0 means 0;
- [NonSerialized]
- private int nBits = -1; // cache BitCount() value
- [NonSerialized]
- private int nBitLength = -1; // cache BitLength() value
- [OnDeserialized]
- private void OnDeserialized(StreamingContext context)
- {
- this.nBits = -1;
- this.nBitLength = -1;
- }
- private static int GetByteLength(int nBits)
- {
- return (nBits + BitsPerByte - 1) / BitsPerByte;
- }
- public static BigInteger Arbitrary(int sizeInBits)
- {
- return new BigInteger(sizeInBits, SecureRandom.ArbitraryRandom);
- }
- private BigInteger(
- int signum,
- int[] mag,
- bool checkMag)
- {
- if (checkMag)
- {
- int i = 0;
- while (i < mag.Length && mag[i] == 0)
- {
- ++i;
- }
- if (i == mag.Length)
- {
- this.sign = 0;
- this.magnitude = ZeroMagnitude;
- }
- else
- {
- this.sign = signum;
- if (i == 0)
- {
- this.magnitude = mag;
- }
- else
- {
- // strip leading 0 words
- this.magnitude = new int[mag.Length - i];
- Array.Copy(mag, i, this.magnitude, 0, this.magnitude.Length);
- }
- }
- }
- else
- {
- this.sign = signum;
- this.magnitude = mag;
- }
- }
- public BigInteger(
- string value)
- : this(value, 10)
- {
- }
- public BigInteger(
- string str,
- int radix)
- {
- if (str.Length == 0)
- throw new FormatException("Zero length BigInteger");
- NumberStyles style;
- int chunk;
- BigInteger r;
- BigInteger rE;
- switch (radix)
- {
- case 2:
- // Is there anyway to restrict to binary digits?
- style = NumberStyles.Integer;
- chunk = chunk2;
- r = radix2;
- rE = radix2E;
- break;
- case 8:
- // Is there anyway to restrict to octal digits?
- style = NumberStyles.Integer;
- chunk = chunk8;
- r = radix8;
- rE = radix8E;
- break;
- case 10:
- // This style seems to handle spaces and minus sign already (our processing redundant?)
- style = NumberStyles.Integer;
- chunk = chunk10;
- r = radix10;
- rE = radix10E;
- break;
- case 16:
- // TODO Should this be HexNumber?
- style = NumberStyles.AllowHexSpecifier;
- chunk = chunk16;
- r = radix16;
- rE = radix16E;
- break;
- default:
- throw new FormatException("Only bases 2, 8, 10, or 16 allowed");
- }
- int index = 0;
- sign = 1;
- if (str[0] == '-')
- {
- if (str.Length == 1)
- throw new FormatException("Zero length BigInteger");
- sign = -1;
- index = 1;
- }
- // strip leading zeros from the string str
- while (index < str.Length && int.Parse(str[index].ToString(), style) == 0)
- {
- index++;
- }
- if (index >= str.Length)
- {
- // zero value - we're done
- sign = 0;
- magnitude = ZeroMagnitude;
- return;
- }
- //////
- // 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?
- //////
- BigInteger b = Zero;
- int next = index + chunk;
- if (next <= str.Length)
- {
- do
- {
- string s = str.Substring(index, chunk);
- ulong i = ulong.Parse(s, style);
- BigInteger bi = CreateUValueOf(i);
- switch (radix)
- {
- case 2:
- // TODO Need this because we are parsing in radix 10 above
- if (i >= 2)
- throw new FormatException("Bad character in radix 2 string: " + s);
- // TODO Parse 64 bits at a time
- b = b.ShiftLeft(1);
- break;
- case 8:
- // TODO Need this because we are parsing in radix 10 above
- if (i >= 8)
- throw new FormatException("Bad character in radix 8 string: " + s);
- // TODO Parse 63 bits at a time
- b = b.ShiftLeft(3);
- break;
- case 16:
- b = b.ShiftLeft(64);
- break;
- default:
- b = b.Multiply(rE);
- break;
- }
- b = b.Add(bi);
- index = next;
- next += chunk;
- }
- while (next <= str.Length);
- }
- if (index < str.Length)
- {
- string s = str.Substring(index);
- ulong i = ulong.Parse(s, style);
- BigInteger bi = CreateUValueOf(i);
- if (b.sign > 0)
- {
- if (radix == 2)
- {
- // NB: Can't reach here since we are parsing one char at a time
- Debug.Assert(false);
- // TODO Parse all bits at once
- // b = b.ShiftLeft(s.Length);
- }
- else if (radix == 8)
- {
- // NB: Can't reach here since we are parsing one char at a time
- Debug.Assert(false);
- // TODO Parse all bits at once
- // b = b.ShiftLeft(s.Length * 3);
- }
- else if (radix == 16)
- {
- b = b.ShiftLeft(s.Length << 2);
- }
- else
- {
- b = b.Multiply(r.Pow(s.Length));
- }
- b = b.Add(bi);
- }
- else
- {
- b = bi;
- }
- }
- // Note: This is the previous (slower) algorithm
- // while (index < value.Length)
- // {
- // char c = value[index];
- // string s = c.ToString();
- // int i = int.Parse(s, style);
- //
- // b = b.Multiply(r).Add(ValueOf(i));
- // index++;
- // }
- magnitude = b.magnitude;
- }
- public BigInteger(
- byte[] bytes)
- : this(bytes, 0, bytes.Length)
- {
- }
- public BigInteger(
- byte[] bytes,
- int offset,
- int length)
- {
- if (length == 0)
- throw new FormatException("Zero length BigInteger");
- // TODO Move this processing into MakeMagnitude (provide sign argument)
- if ((sbyte)bytes[offset] < 0)
- {
- this.sign = -1;
- int end = offset + length;
- int iBval;
- // strip leading sign bytes
- for (iBval = offset; iBval < end && ((sbyte)bytes[iBval] == -1); iBval++)
- {
- }
- if (iBval >= end)
- {
- this.magnitude = One.magnitude;
- }
- else
- {
- int numBytes = end - iBval;
- #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || _UNITY_2021_2_OR_NEWER_
- Span<byte> inverse = numBytes <= 512
- ? stackalloc byte[numBytes]
- : new byte[numBytes];
- #else
- byte[] inverse = new byte[numBytes];
- #endif
- int index = 0;
- while (index < numBytes)
- {
- inverse[index++] = (byte)~bytes[iBval++];
- }
- Debug.Assert(iBval == end);
- while (inverse[--index] == byte.MaxValue)
- {
- inverse[index] = byte.MinValue;
- }
- inverse[index]++;
- this.magnitude = MakeMagnitude(inverse);
- }
- }
- else
- {
- // strip leading zero bytes and return magnitude bytes
- this.magnitude = MakeMagnitude(bytes, offset, length);
- this.sign = this.magnitude.Length > 0 ? 1 : 0;
- }
- }
- private static int[] MakeMagnitude(byte[] bytes)
- {
- return MakeMagnitude(bytes, 0, bytes.Length);
- }
- private static int[] MakeMagnitude(byte[] bytes, int offset, int length)
- {
- #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || _UNITY_2021_2_OR_NEWER_
- return MakeMagnitude(bytes.AsSpan(offset, length));
- #else
- int end = offset + length;
- // strip leading zeros
- int firstSignificant;
- for (firstSignificant = offset; firstSignificant < end && bytes[firstSignificant] == 0; firstSignificant++)
- {
- }
- if (firstSignificant >= end)
- return ZeroMagnitude;
- int nInts = (end - firstSignificant + 3) / BytesPerInt;
- int bCount = (end - firstSignificant) % BytesPerInt;
- if (bCount == 0)
- {
- bCount = BytesPerInt;
- }
- if (nInts < 1)
- return ZeroMagnitude;
- int[] mag = new int[nInts];
- int v = 0;
- int magnitudeIndex = 0;
- for (int i = firstSignificant; i < end; ++i)
- {
- v <<= 8;
- v |= bytes[i] & 0xff;
- bCount--;
- if (bCount <= 0)
- {
- mag[magnitudeIndex] = v;
- magnitudeIndex++;
- bCount = BytesPerInt;
- v = 0;
- }
- }
- if (magnitudeIndex < mag.Length)
- {
- mag[magnitudeIndex] = v;
- }
- return mag;
- #endif
- }
- #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || _UNITY_2021_2_OR_NEWER_
- private static int[] MakeMagnitude(ReadOnlySpan<byte> bytes)
- {
- int end = bytes.Length;
- // strip leading zeros
- int firstSignificant;
- for (firstSignificant = 0; firstSignificant < end && bytes[firstSignificant] == 0; firstSignificant++)
- {
- }
- if (firstSignificant >= end)
- return ZeroMagnitude;
- int nInts = (end - firstSignificant + 3) / BytesPerInt;
- int bCount = (end - firstSignificant) % BytesPerInt;
- if (bCount == 0)
- {
- bCount = BytesPerInt;
- }
- if (nInts < 1)
- return ZeroMagnitude;
- int[] mag = new int[nInts];
- int v = 0;
- int magnitudeIndex = 0;
- for (int i = firstSignificant; i < end; ++i)
- {
- v <<= 8;
- v |= bytes[i] & 0xff;
- bCount--;
- if (bCount <= 0)
- {
- mag[magnitudeIndex] = v;
- magnitudeIndex++;
- bCount = BytesPerInt;
- v = 0;
- }
- }
- if (magnitudeIndex < mag.Length)
- {
- mag[magnitudeIndex] = v;
- }
- return mag;
- }
- #endif
- public BigInteger(int sign, byte[] bytes)
- : this(sign, bytes, 0, bytes.Length)
- {
- }
- public BigInteger(int sign, byte[] bytes, int offset, int length)
- {
- if (sign < -1 || sign > 1)
- throw new FormatException("Invalid sign value");
- if (sign == 0)
- {
- this.sign = 0;
- this.magnitude = ZeroMagnitude;
- }
- else
- {
- // copy bytes
- this.magnitude = MakeMagnitude(bytes, offset, length);
- this.sign = this.magnitude.Length < 1 ? 0 : sign;
- }
- }
- #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || _UNITY_2021_2_OR_NEWER_
- public BigInteger(int sign, ReadOnlySpan<byte> bytes)
- {
- if (sign < -1 || sign > 1)
- throw new FormatException("Invalid sign value");
- if (sign == 0)
- {
- this.sign = 0;
- this.magnitude = ZeroMagnitude;
- }
- else
- {
- // copy bytes
- this.magnitude = MakeMagnitude(bytes);
- this.sign = this.magnitude.Length < 1 ? 0 : sign;
- }
- }
- #endif
- public BigInteger(
- int sizeInBits,
- Random random)
- {
- if (sizeInBits < 0)
- throw new ArgumentException("sizeInBits must be non-negative");
- this.nBits = -1;
- this.nBitLength = -1;
- if (sizeInBits == 0)
- {
- this.sign = 0;
- this.magnitude = ZeroMagnitude;
- return;
- }
- int nBytes = GetByteLength(sizeInBits);
- #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || _UNITY_2021_2_OR_NEWER_
- Span<byte> b = nBytes <= 512
- ? stackalloc byte[nBytes]
- : new byte[nBytes];
- #else
- byte[] b = new byte[nBytes];
- #endif
- random.NextBytes(b);
- // strip off any excess bits in the MSB
- int xBits = BitsPerByte * nBytes - sizeInBits;
- b[0] &= (byte)(255U >> xBits);
- this.magnitude = MakeMagnitude(b);
- this.sign = this.magnitude.Length < 1 ? 0 : 1;
- }
- public BigInteger(
- int bitLength,
- int certainty,
- Random random)
- {
- if (bitLength < 2)
- throw new ArithmeticException("bitLength < 2");
- this.sign = 1;
- this.nBitLength = bitLength;
- if (bitLength == 2)
- {
- this.magnitude = random.Next(2) == 0
- ? Two.magnitude
- : Three.magnitude;
- return;
- }
-
- int nBytes = GetByteLength(bitLength);
- #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || _UNITY_2021_2_OR_NEWER_
- Span<byte> b = nBytes <= 512
- ? stackalloc byte[nBytes]
- : new byte[nBytes];
- #else
- byte[] b = new byte[nBytes];
- #endif
- int xBits = BitsPerByte * nBytes - bitLength;
- byte mask = (byte)(255U >> xBits);
- byte lead = (byte)(1 << (7 - xBits));
- for (;;)
- {
- random.NextBytes(b);
- // strip off any excess bits in the MSB
- b[0] &= mask;
- // ensure the leading bit is 1 (to meet the strength requirement)
- b[0] |= lead;
- // ensure the trailing bit is 1 (i.e. must be odd)
- b[nBytes - 1] |= 1;
- this.magnitude = MakeMagnitude(b);
- this.nBits = -1;
- if (certainty < 1)
- break;
- if (CheckProbablePrime(certainty, random, true))
- break;
- for (int j = 1; j < (magnitude.Length - 1); ++j)
- {
- this.magnitude[j] ^= random.Next();
- if (CheckProbablePrime(certainty, random, true))
- return;
- }
- }
- }
- public BigInteger Abs()
- {
- return sign >= 0 ? this : Negate();
- }
- /**
- * return a = a + b - b preserved.
- */
- private static int[] AddMagnitudes(
- int[] a,
- int[] b)
- {
- int tI = a.Length - 1;
- int vI = b.Length - 1;
- long m = 0;
- while (vI >= 0)
- {
- m += ((long)(uint)a[tI] + (long)(uint)b[vI--]);
- a[tI--] = (int)m;
- m = (long)((ulong)m >> 32);
- }
- if (m != 0)
- {
- while (tI >= 0 && ++a[tI--] == 0)
- {
- }
- }
- return a;
- }
- public BigInteger Add(
- BigInteger value)
- {
- if (this.sign == 0)
- return value;
- if (this.sign != value.sign)
- {
- if (value.sign == 0)
- return this;
- if (value.sign < 0)
- return Subtract(value.Negate());
- return value.Subtract(Negate());
- }
- return AddToMagnitude(value.magnitude);
- }
- private BigInteger AddToMagnitude(
- int[] magToAdd)
- {
- int[] big, small;
- if (this.magnitude.Length < magToAdd.Length)
- {
- big = magToAdd;
- small = this.magnitude;
- }
- else
- {
- big = this.magnitude;
- small = magToAdd;
- }
- // Conservatively avoid over-allocation when no overflow possible
- uint limit = uint.MaxValue;
- if (big.Length == small.Length)
- limit -= (uint) small[0];
- bool possibleOverflow = (uint) big[0] >= limit;
- int[] bigCopy;
- if (possibleOverflow)
- {
- bigCopy = new int[big.Length + 1];
- big.CopyTo(bigCopy, 1);
- }
- else
- {
- bigCopy = (int[]) big.Clone();
- }
- bigCopy = AddMagnitudes(bigCopy, small);
- return new BigInteger(this.sign, bigCopy, possibleOverflow);
- }
- public BigInteger And(
- BigInteger value)
- {
- if (this.sign == 0 || value.sign == 0)
- {
- return Zero;
- }
- int[] aMag = this.sign > 0
- ? this.magnitude
- : Add(One).magnitude;
- int[] bMag = value.sign > 0
- ? value.magnitude
- : value.Add(One).magnitude;
- bool resultNeg = sign < 0 && value.sign < 0;
- int resultLength = System.Math.Max(aMag.Length, bMag.Length);
- int[] resultMag = new int[resultLength];
- int aStart = resultMag.Length - aMag.Length;
- int bStart = resultMag.Length - bMag.Length;
- for (int i = 0; i < resultMag.Length; ++i)
- {
- int aWord = i >= aStart ? aMag[i - aStart] : 0;
- int bWord = i >= bStart ? bMag[i - bStart] : 0;
- if (this.sign < 0)
- {
- aWord = ~aWord;
- }
- if (value.sign < 0)
- {
- bWord = ~bWord;
- }
- resultMag[i] = aWord & bWord;
- if (resultNeg)
- {
- resultMag[i] = ~resultMag[i];
- }
- }
- BigInteger result = new BigInteger(1, resultMag, true);
- // TODO Optimise this case
- if (resultNeg)
- {
- result = result.Not();
- }
- return result;
- }
- public BigInteger AndNot(
- BigInteger val)
- {
- return And(val.Not());
- }
- public int BitCount
- {
- get
- {
- if (nBits == -1)
- {
- if (sign < 0)
- {
- // TODO Optimise this case
- nBits = Not().BitCount;
- }
- else
- {
- int sum = 0;
- for (int i = 0; i < magnitude.Length; ++i)
- {
- sum += BitCnt(magnitude[i]);
- }
- nBits = sum;
- }
- }
- return nBits;
- }
- }
- public static int BitCnt(int i)
- {
- #if NETCOREAPP3_0_OR_GREATER
- return BitOperations.PopCount((uint)i);
- #else
- uint u = (uint)i;
- u = u - ((u >> 1) & 0x55555555);
- u = (u & 0x33333333) + ((u >> 2) & 0x33333333);
- u = (u + (u >> 4)) & 0x0f0f0f0f;
- u += (u >> 8);
- u += (u >> 16);
- u &= 0x3f;
- return (int)u;
- #endif
- }
- private static int CalcBitLength(int sign, int indx, int[] mag)
- {
- for (;;)
- {
- if (indx >= mag.Length)
- return 0;
- if (mag[indx] != 0)
- break;
- ++indx;
- }
- // bit length for everything after the first int
- int bitLength = 32 * ((mag.Length - indx) - 1);
- // and determine bitlength of first int
- int firstMag = mag[indx];
- bitLength += BitLen(firstMag);
- // Check for negative powers of two
- if (sign < 0 && ((firstMag & -firstMag) == firstMag))
- {
- do
- {
- if (++indx >= mag.Length)
- {
- --bitLength;
- break;
- }
- }
- while (mag[indx] == 0);
- }
- return bitLength;
- }
- public int BitLength
- {
- get
- {
- if (nBitLength == -1)
- {
- nBitLength = sign == 0
- ? 0
- : CalcBitLength(sign, 0, magnitude);
- }
- return nBitLength;
- }
- }
- private static int BitLen(byte b)
- {
- #if NETCOREAPP3_0_OR_GREATER
- return 32 - BitOperations.LeadingZeroCount((uint)b);
- #else
- return BitLengthTable[b];
- #endif
- }
- private static int BitLen(int w)
- {
- #if NETCOREAPP3_0_OR_GREATER
- return 32 - BitOperations.LeadingZeroCount((uint)w);
- #else
- uint v = (uint)w;
- uint t = v >> 24;
- if (t != 0)
- return 24 + BitLengthTable[t];
- t = v >> 16;
- if (t != 0)
- return 16 + BitLengthTable[t];
- t = v >> 8;
- if (t != 0)
- return 8 + BitLengthTable[t];
- return BitLengthTable[v];
- #endif
- }
- private bool QuickPow2Check()
- {
- return sign > 0 && nBits == 1;
- }
- public int CompareTo(BigInteger other)
- {
- if (other == null)
- return 1;
- return sign < other.sign
- ? -1
- : sign > other.sign
- ? 1
- : sign == 0
- ? 0
- : sign * CompareNoLeadingZeroes(0, magnitude, 0, other.magnitude);
- }
- /**
- * unsigned comparison on two arrays - note the arrays may
- * start with leading zeros.
- */
- private static int CompareTo(
- int xIndx,
- int[] x,
- int yIndx,
- int[] y)
- {
- while (xIndx != x.Length && x[xIndx] == 0)
- {
- xIndx++;
- }
- while (yIndx != y.Length && y[yIndx] == 0)
- {
- yIndx++;
- }
- return CompareNoLeadingZeroes(xIndx, x, yIndx, y);
- }
- private static int CompareNoLeadingZeroes(
- int xIndx,
- int[] x,
- int yIndx,
- int[] y)
- {
- int diff = (x.Length - y.Length) - (xIndx - yIndx);
- if (diff != 0)
- {
- return diff < 0 ? -1 : 1;
- }
- // lengths of magnitudes the same, test the magnitude values
- while (xIndx < x.Length)
- {
- uint v1 = (uint)x[xIndx++];
- uint v2 = (uint)y[yIndx++];
- if (v1 != v2)
- return v1 < v2 ? -1 : 1;
- }
- return 0;
- }
- /**
- * return z = x / y - done in place (z value preserved, x contains the
- * remainder)
- */
- private int[] Divide(
- int[] x,
- int[] y)
- {
- int xStart = 0;
- while (xStart < x.Length && x[xStart] == 0)
- {
- ++xStart;
- }
- int yStart = 0;
- while (yStart < y.Length && y[yStart] == 0)
- {
- ++yStart;
- }
- Debug.Assert(yStart < y.Length);
- int xyCmp = CompareNoLeadingZeroes(xStart, x, yStart, y);
- int[] count;
- if (xyCmp > 0)
- {
- int yBitLength = CalcBitLength(1, yStart, y);
- int xBitLength = CalcBitLength(1, xStart, x);
- int shift = xBitLength - yBitLength;
- int[] iCount;
- int iCountStart = 0;
- int[] c;
- int cStart = 0;
- int cBitLength = yBitLength;
- if (shift > 0)
- {
- // iCount = ShiftLeft(One.magnitude, shift);
- iCount = new int[(shift >> 5) + 1];
- iCount[0] = 1 << (shift % 32);
- c = ShiftLeft(y, shift);
- cBitLength += shift;
- }
- else
- {
- iCount = new int[] { 1 };
- int len = y.Length - yStart;
- c = new int[len];
- Array.Copy(y, yStart, c, 0, len);
- }
- count = new int[iCount.Length];
- for (;;)
- {
- if (cBitLength < xBitLength
- || CompareNoLeadingZeroes(xStart, x, cStart, c) >= 0)
- {
- Subtract(xStart, x, cStart, c);
- AddMagnitudes(count, iCount);
- while (x[xStart] == 0)
- {
- if (++xStart == x.Length)
- return count;
- }
- //xBitLength = CalcBitLength(xStart, x);
- xBitLength = 32 * (x.Length - xStart - 1) + BitLen(x[xStart]);
- if (xBitLength <= yBitLength)
- {
- if (xBitLength < yBitLength)
- return count;
- xyCmp = CompareNoLeadingZeroes(xStart, x, yStart, y);
- if (xyCmp <= 0)
- break;
- }
- }
- shift = cBitLength - xBitLength;
- // NB: The case where c[cStart] is 1-bit is harmless
- if (shift == 1)
- {
- uint firstC = (uint) c[cStart] >> 1;
- uint firstX = (uint) x[xStart];
- if (firstC > firstX)
- ++shift;
- }
- if (shift < 2)
- {
- ShiftRightOneInPlace(cStart, c);
- --cBitLength;
- ShiftRightOneInPlace(iCountStart, iCount);
- }
- else
- {
- ShiftRightInPlace(cStart, c, shift);
- cBitLength -= shift;
- ShiftRightInPlace(iCountStart, iCount, shift);
- }
- //cStart = c.Length - ((cBitLength + 31) / 32);
- while (c[cStart] == 0)
- {
- ++cStart;
- }
- while (iCount[iCountStart] == 0)
- {
- ++iCountStart;
- }
- }
- }
- else
- {
- count = new int[1];
- }
- if (xyCmp == 0)
- {
- AddMagnitudes(count, One.magnitude);
- Array.Clear(x, xStart, x.Length - xStart);
- }
- return count;
- }
- public BigInteger Divide(
- BigInteger val)
- {
- if (val.sign == 0)
- throw new ArithmeticException("Division by zero error");
- if (sign == 0)
- return Zero;
- if (val.QuickPow2Check()) // val is power of two
- {
- BigInteger result = this.Abs().ShiftRight(val.Abs().BitLength - 1);
- return val.sign == this.sign ? result : result.Negate();
- }
- int[] mag = (int[]) this.magnitude.Clone();
- return new BigInteger(this.sign * val.sign, Divide(mag, val.magnitude), true);
- }
- public BigInteger[] DivideAndRemainder(
- BigInteger val)
- {
- if (val.sign == 0)
- throw new ArithmeticException("Division by zero error");
- BigInteger[] biggies = new BigInteger[2];
- if (sign == 0)
- {
- biggies[0] = Zero;
- biggies[1] = Zero;
- }
- else if (val.QuickPow2Check()) // val is power of two
- {
- int e = val.Abs().BitLength - 1;
- BigInteger quotient = this.Abs().ShiftRight(e);
- int[] remainder = this.LastNBits(e);
- biggies[0] = val.sign == this.sign ? quotient : quotient.Negate();
- biggies[1] = new BigInteger(this.sign, remainder, true);
- }
- else
- {
- int[] remainder = (int[]) this.magnitude.Clone();
- int[] quotient = Divide(remainder, val.magnitude);
- biggies[0] = new BigInteger(this.sign * val.sign, quotient, true);
- biggies[1] = new BigInteger(this.sign, remainder, true);
- }
- return biggies;
- }
- public override bool Equals(object obj)
- {
- if (obj == this)
- return true;
- if (!(obj is BigInteger biggie))
- return false;
- return sign == biggie.sign && IsEqualMagnitude(biggie);
- }
- public bool Equals(BigInteger other)
- {
- if (other == this)
- return true;
- if (other == null)
- return false;
- return sign == other.sign && IsEqualMagnitude(other);
- }
- private bool IsEqualMagnitude(BigInteger x)
- {
- int[] xMag = x.magnitude;
- if (magnitude.Length != x.magnitude.Length)
- return false;
- for (int i = 0; i < magnitude.Length; i++)
- {
- if (magnitude[i] != x.magnitude[i])
- return false;
- }
- return true;
- }
- public BigInteger Gcd(
- BigInteger value)
- {
- if (value.sign == 0)
- return Abs();
- if (sign == 0)
- return value.Abs();
- BigInteger r;
- BigInteger u = this;
- BigInteger v = value;
- while (v.sign != 0)
- {
- r = u.Mod(v);
- u = v;
- v = r;
- }
- return u;
- }
- public override int GetHashCode()
- {
- int hc = magnitude.Length;
- if (magnitude.Length > 0)
- {
- hc ^= magnitude[0];
- if (magnitude.Length > 1)
- {
- hc ^= magnitude[magnitude.Length - 1];
- }
- }
- return sign < 0 ? ~hc : hc;
- }
- // TODO Make public?
- private BigInteger Inc()
- {
- if (this.sign == 0)
- return One;
- if (this.sign < 0)
- return new BigInteger(-1, doSubBigLil(this.magnitude, One.magnitude), true);
- return AddToMagnitude(One.magnitude);
- }
- public int IntValue
- {
- get
- {
- if (sign == 0)
- return 0;
- int n = magnitude.Length;
- int v = magnitude[n - 1];
- return sign < 0 ? -v : v;
- }
- }
- public int IntValueExact
- {
- get
- {
- if (BitLength > 31)
- throw new ArithmeticException("BigInteger out of int range");
- return IntValue;
- }
- }
- /**
- * return whether or not a BigInteger is probably prime with a
- * probability of 1 - (1/2)**certainty.
- * <p>From Knuth Vol 2, pg 395.</p>
- */
- public bool IsProbablePrime(int certainty)
- {
- return IsProbablePrime(certainty, false);
- }
- internal bool IsProbablePrime(int certainty, bool randomlySelected)
- {
- if (certainty <= 0)
- return true;
- BigInteger n = Abs();
- if (!n.TestBit(0))
- return n.Equals(Two);
- if (n.Equals(One))
- return false;
- return n.CheckProbablePrime(certainty, SecureRandom.ArbitraryRandom, randomlySelected);
- }
- private bool CheckProbablePrime(int certainty, Random random, bool randomlySelected)
- {
- Debug.Assert(certainty > 0);
- Debug.Assert(CompareTo(Two) > 0);
- Debug.Assert(TestBit(0));
- // Try to reduce the penalty for really small numbers
- int numLists = System.Math.Min(BitLength - 1, primeLists.Length);
- for (int i = 0; i < numLists; ++i)
- {
- int test = Remainder(primeProducts[i]);
- int[] primeList = primeLists[i];
- for (int j = 0; j < primeList.Length; ++j)
- {
- int prime = primeList[j];
- int qRem = test % prime;
- if (qRem == 0)
- {
- // We may find small numbers in the list
- return BitLength < 16 && IntValue == prime;
- }
- }
- }
- // 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?
- return RabinMillerTest(certainty, random, randomlySelected);
- // return SolovayStrassenTest(certainty, random);
- // bool rbTest = RabinMillerTest(certainty, random);
- // bool ssTest = SolovayStrassenTest(certainty, random);
- //
- // Debug.Assert(rbTest == ssTest);
- //
- // return rbTest;
- }
- public bool RabinMillerTest(int certainty, Random random)
- {
- return RabinMillerTest(certainty, random, false);
- }
- internal bool RabinMillerTest(int certainty, Random random, bool randomlySelected)
- {
- int bits = BitLength;
- Debug.Assert(certainty > 0);
- Debug.Assert(bits > 2);
- Debug.Assert(TestBit(0));
- int iterations = ((certainty - 1) / 2) + 1;
- if (randomlySelected)
- {
- int itersFor100Cert = bits >= 1024 ? 4
- : bits >= 512 ? 8
- : bits >= 256 ? 16
- : 50;
- if (certainty < 100)
- {
- iterations = System.Math.Min(itersFor100Cert, iterations);
- }
- else
- {
- iterations -= 50;
- iterations += itersFor100Cert;
- }
- }
- // let n = 1 + d . 2^s
- BigInteger n = this;
- int s = n.GetLowestSetBitMaskFirst(-1 << 1);
- Debug.Assert(s >= 1);
- BigInteger r = n.ShiftRight(s);
- // NOTE: Avoid conversion to/from Montgomery form and check for R/-R as result instead
- BigInteger montRadix = One.ShiftLeft(32 * n.magnitude.Length).Remainder(n);
- BigInteger minusMontRadix = n.Subtract(montRadix);
- do
- {
- BigInteger a;
- do
- {
- a = new BigInteger(n.BitLength, random);
- }
- while (a.sign == 0 || a.CompareTo(n) >= 0
- || a.IsEqualMagnitude(montRadix) || a.IsEqualMagnitude(minusMontRadix));
- BigInteger y = ModPowMonty(a, r, n, false);
- if (!y.Equals(montRadix))
- {
- int j = 0;
- while (!y.Equals(minusMontRadix))
- {
- if (++j == s)
- return false;
- y = ModPowMonty(y, Two, n, false);
- if (y.Equals(montRadix))
- return false;
- }
- }
- }
- while (--iterations > 0);
- return true;
- }
- // private bool SolovayStrassenTest(
- // int certainty,
- // Random random)
- // {
- // Debug.Assert(certainty > 0);
- // Debug.Assert(CompareTo(Two) > 0);
- // Debug.Assert(TestBit(0));
- //
- // BigInteger n = this;
- // BigInteger nMinusOne = n.Subtract(One);
- // BigInteger e = nMinusOne.ShiftRight(1);
- //
- // do
- // {
- // BigInteger a;
- // do
- // {
- // a = new BigInteger(nBitLength, random);
- // }
- // // NB: Spec says 0 < x < n, but 1 is trivial
- // while (a.CompareTo(One) <= 0 || a.CompareTo(n) >= 0);
- //
- //
- // // TODO Check this is redundant given the way Jacobi() works?
- //// if (!a.Gcd(n).Equals(One))
- //// return false;
- //
- // int x = Jacobi(a, n);
- //
- // if (x == 0)
- // return false;
- //
- // BigInteger check = a.ModPow(e, n);
- //
- // if (x == 1 && !check.Equals(One))
- // return false;
- //
- // if (x == -1 && !check.Equals(nMinusOne))
- // return false;
- //
- // --certainty;
- // }
- // while (certainty > 0);
- //
- // return true;
- // }
- //
- // private static int Jacobi(
- // BigInteger a,
- // BigInteger b)
- // {
- // Debug.Assert(a.sign >= 0);
- // Debug.Assert(b.sign > 0);
- // Debug.Assert(b.TestBit(0));
- // Debug.Assert(a.CompareTo(b) < 0);
- //
- // int totalS = 1;
- // for (;;)
- // {
- // if (a.sign == 0)
- // return 0;
- //
- // if (a.Equals(One))
- // break;
- //
- // int e = a.GetLowestSetBit();
- //
- // int bLsw = b.magnitude[b.magnitude.Length - 1];
- // if ((e & 1) != 0 && ((bLsw & 7) == 3 || (bLsw & 7) == 5))
- // totalS = -totalS;
- //
- // // TODO Confirm this is faster than later a1.Equals(One) test
- // if (a.BitLength == e + 1)
- // break;
- // BigInteger a1 = a.ShiftRight(e);
- //// if (a1.Equals(One))
- //// break;
- //
- // int a1Lsw = a1.magnitude[a1.magnitude.Length - 1];
- // if ((bLsw & 3) == 3 && (a1Lsw & 3) == 3)
- // totalS = -totalS;
- //
- //// a = b.Mod(a1);
- // a = b.Remainder(a1);
- // b = a1;
- // }
- // return totalS;
- // }
- public long LongValue
- {
- get
- {
- if (sign == 0)
- return 0;
- int n = magnitude.Length;
- long v = magnitude[n - 1] & IMASK;
- if (n > 1)
- {
- v |= (magnitude[n - 2] & IMASK) << 32;
- }
- return sign < 0 ? -v : v;
- }
- }
- public long LongValueExact
- {
- get
- {
- if (BitLength > 63)
- throw new ArithmeticException("BigInteger out of long range");
- return LongValue;
- }
- }
- public BigInteger Max(
- BigInteger value)
- {
- return CompareTo(value) > 0 ? this : value;
- }
- public BigInteger Min(
- BigInteger value)
- {
- return CompareTo(value) < 0 ? this : value;
- }
- public BigInteger Mod(
- BigInteger m)
- {
- if (m.sign < 1)
- throw new ArithmeticException("Modulus must be positive");
- BigInteger biggie = Remainder(m);
- return (biggie.sign >= 0 ? biggie : biggie.Add(m));
- }
- public BigInteger ModInverse(
- BigInteger m)
- {
- if (m.sign < 1)
- throw new ArithmeticException("Modulus must be positive");
- // 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(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())
- {
- return ModInversePow2(m);
- }
- BigInteger d = this.Remainder(m);
- BigInteger x;
- BigInteger gcd = ExtEuclid(d, m, out x);
- if (!gcd.Equals(One))
- throw new ArithmeticException("Numbers not relatively prime.");
- if (x.sign < 0)
- {
- x = x.Add(m);
- }
- return x;
- }
- private BigInteger ModInversePow2(BigInteger m)
- {
- Debug.Assert(m.SignValue > 0);
- Debug.Assert(m.BitCount == 1);
- if (!TestBit(0))
- {
- throw new ArithmeticException("Numbers not relatively prime.");
- }
- int pow = m.BitLength - 1;
- long inv64 = (long)Raw.Mod.Inverse64((ulong)LongValue);
- if (pow < 64)
- {
- inv64 &= ((1L << pow) - 1);
- }
- BigInteger x = ValueOf(inv64);
- if (pow > 64)
- {
- BigInteger d = this.Remainder(m);
- int bitsCorrect = 64;
- do
- {
- BigInteger t = x.Multiply(d).Remainder(m);
- x = x.Multiply(Two.Subtract(t)).Remainder(m);
- bitsCorrect <<= 1;
- }
- while (bitsCorrect < pow);
- }
- if (x.sign < 0)
- {
- x = x.Add(m);
- }
- return x;
- }
- /**
- * Calculate the numbers u1, u2, and u3 such that:
- *
- * u1 * a + u2 * b = u3
- *
- * where u3 is the greatest common divider of a and b.
- * a and b using the extended Euclid algorithm (refer p. 323
- * of The Art of Computer Programming vol 2, 2nd ed).
- * This also seems to have the side effect of calculating
- * some form of multiplicative inverse.
- *
- * @param a First number to calculate gcd for
- * @param b Second number to calculate gcd for
- * @param u1Out the return object for the u1 value
- * @return The greatest common divisor of a and b
- */
- private static BigInteger ExtEuclid(BigInteger a, BigInteger b, out BigInteger u1Out)
- {
- BigInteger u1 = One, v1 = Zero;
- BigInteger u3 = a, v3 = b;
- if (v3.sign > 0)
- {
- for (;;)
- {
- BigInteger[] q = u3.DivideAndRemainder(v3);
- u3 = v3;
- v3 = q[1];
- BigInteger oldU1 = u1;
- u1 = v1;
- if (v3.sign <= 0)
- break;
- v1 = oldU1.Subtract(v1.Multiply(q[0]));
- }
- }
- u1Out = u1;
- return u3;
- }
- private static void ZeroOut(
- int[] x)
- {
- Array.Clear(x, 0, x.Length);
- }
- public BigInteger ModPow(BigInteger e, BigInteger m)
- {
- if (m.sign < 1)
- throw new ArithmeticException("Modulus must be positive");
- if (m.Equals(One))
- return Zero;
- if (e.sign == 0)
- return One;
- if (sign == 0)
- return Zero;
- bool negExp = e.sign < 0;
- if (negExp)
- e = e.Negate();
- BigInteger result = this.Mod(m);
- if (!e.Equals(One))
- {
- if ((m.magnitude[m.magnitude.Length - 1] & 1) == 0)
- {
- result = ModPowBarrett(result, e, m);
- }
- else
- {
- result = ModPowMonty(result, e, m, true);
- }
- }
- if (negExp)
- result = result.ModInverse(m);
- return result;
- }
- private static BigInteger ModPowBarrett(BigInteger b, BigInteger e, BigInteger m)
- {
- int k = m.magnitude.Length;
- BigInteger mr = One.ShiftLeft((k + 1) << 5);
- BigInteger yu = One.ShiftLeft(k << 6).Divide(m);
- // Sliding window from MSW to LSW
- int extraBits = 0, expLength = e.BitLength;
- while (expLength > ExpWindowThresholds[extraBits])
- {
- ++extraBits;
- }
- int numPowers = 1 << extraBits;
- BigInteger[] oddPowers = new BigInteger[numPowers];
- oddPowers[0] = b;
- BigInteger b2 = ReduceBarrett(b.Square(), m, mr, yu);
- for (int i = 1; i < numPowers; ++i)
- {
- oddPowers[i] = ReduceBarrett(oddPowers[i - 1].Multiply(b2), m, mr, yu);
- }
- int[] windowList = GetWindowList(e.magnitude, extraBits);
- Debug.Assert(windowList.Length > 0);
- int window = windowList[0];
- int mult = window & 0xFF, lastZeroes = window >> 8;
- BigInteger y;
- if (mult == 1)
- {
- y = b2;
- --lastZeroes;
- }
- else
- {
- y = oddPowers[mult >> 1];
- }
- int windowPos = 1;
- while ((window = windowList[windowPos++]) != -1)
- {
- mult = window & 0xFF;
- int bits = lastZeroes + BitLen((byte)mult);
- for (int j = 0; j < bits; ++j)
- {
- y = ReduceBarrett(y.Square(), m, mr, yu);
- }
- y = ReduceBarrett(y.Multiply(oddPowers[mult >> 1]), m, mr, yu);
- lastZeroes = window >> 8;
- }
- for (int i = 0; i < lastZeroes; ++i)
- {
- y = ReduceBarrett(y.Square(), m, mr, yu);
- }
- return y;
- }
- private static BigInteger ReduceBarrett(BigInteger x, BigInteger m, BigInteger mr, BigInteger yu)
- {
- int xLen = x.BitLength, mLen = m.BitLength;
- if (xLen < mLen)
- return x;
- if (xLen - mLen > 1)
- {
- int k = m.magnitude.Length;
- BigInteger q1 = x.DivideWords(k - 1);
- BigInteger q2 = q1.Multiply(yu); // TODO Only need partial multiplication here
- BigInteger q3 = q2.DivideWords(k + 1);
- BigInteger r1 = x.RemainderWords(k + 1);
- BigInteger r2 = q3.Multiply(m); // TODO Only need partial multiplication here
- BigInteger r3 = r2.RemainderWords(k + 1);
- x = r1.Subtract(r3);
- if (x.sign < 0)
- {
- x = x.Add(mr);
- }
- }
- while (x.CompareTo(m) >= 0)
- {
- x = x.Subtract(m);
- }
- return x;
- }
- private static BigInteger ModPowMonty(BigInteger b, BigInteger e, BigInteger m, bool convert)
- {
- int n = m.magnitude.Length;
- int powR = 32 * n;
- bool smallMontyModulus = m.BitLength + 2 <= powR;
- uint mDash = (uint)m.GetMQuote();
- // tmp = this * R mod m
- if (convert)
- {
- b = b.ShiftLeft(powR).Remainder(m);
- }
- int[] yAccum = new int[n + 1];
- int[] zVal = b.magnitude;
- Debug.Assert(zVal.Length <= n);
- if (zVal.Length < n)
- {
- int[] tmp = new int[n];
- zVal.CopyTo(tmp, n - zVal.Length);
- zVal = tmp;
- }
- // Sliding window from MSW to LSW
- int extraBits = 0;
- // Filter the common case of small RSA exponents with few bits set
- if (e.magnitude.Length > 1 || e.BitCount > 2)
- {
- int expLength = e.BitLength;
- while (expLength > ExpWindowThresholds[extraBits])
- {
- ++extraBits;
- }
- }
- int numPowers = 1 << extraBits;
- int[][] oddPowers = new int[numPowers][];
- oddPowers[0] = zVal;
- int[] zSquared = Arrays.Clone(zVal);
- SquareMonty(yAccum, zSquared, m.magnitude, mDash, smallMontyModulus);
- for (int i = 1; i < numPowers; ++i)
- {
- oddPowers[i] = Arrays.Clone(oddPowers[i - 1]);
- MultiplyMonty(yAccum, oddPowers[i], zSquared, m.magnitude, mDash, smallMontyModulus);
- }
- int[] windowList = GetWindowList(e.magnitude, extraBits);
- Debug.Assert(windowList.Length > 1);
- int window = windowList[0];
- int mult = window & 0xFF, lastZeroes = window >> 8;
- int[] yVal;
- if (mult == 1)
- {
- yVal = zSquared;
- --lastZeroes;
- }
- else
- {
- yVal = Arrays.Clone(oddPowers[mult >> 1]);
- }
- int windowPos = 1;
- while ((window = windowList[windowPos++]) != -1)
- {
- mult = window & 0xFF;
- int bits = lastZeroes + BitLen((byte)mult);
- for (int j = 0; j < bits; ++j)
- {
- SquareMonty(yAccum, yVal, m.magnitude, mDash, smallMontyModulus);
- }
- MultiplyMonty(yAccum, yVal, oddPowers[mult >> 1], m.magnitude, mDash, smallMontyModulus);
- lastZeroes = window >> 8;
- }
- for (int i = 0; i < lastZeroes; ++i)
- {
- SquareMonty(yAccum, yVal, m.magnitude, mDash, smallMontyModulus);
- }
- if (convert)
- {
- // Return y * R^(-1) mod m
- MontgomeryReduce(yVal, m.magnitude, mDash);
- }
- else if (smallMontyModulus && CompareTo(0, yVal, 0, m.magnitude) >= 0)
- {
- Subtract(0, yVal, 0, m.magnitude);
- }
- return new BigInteger(1, yVal, true);
- }
- private static int[] GetWindowList(int[] mag, int extraBits)
- {
- int v = mag[0];
- Debug.Assert(v != 0);
- int leadingBits = BitLen(v);
- int resultSize = (((mag.Length - 1) << 5) + leadingBits) / (1 + extraBits) + 2;
- int[] result = new int[resultSize];
- int resultPos = 0;
- int bitPos = 33 - leadingBits;
- v <<= bitPos;
- int mult = 1, multLimit = 1 << extraBits;
- int zeroes = 0;
- int i = 0;
- for (; ; )
- {
- for (; bitPos < 32; ++bitPos)
- {
- if (mult < multLimit)
- {
- mult = (mult << 1) | (int)((uint)v >> 31);
- }
- else if (v < 0)
- {
- result[resultPos++] = CreateWindowEntry(mult, zeroes);
- mult = 1;
- zeroes = 0;
- }
- else
- {
- ++zeroes;
- }
- v <<= 1;
- }
- if (++i == mag.Length)
- {
- result[resultPos++] = CreateWindowEntry(mult, zeroes);
- break;
- }
- v = mag[i];
- bitPos = 0;
- }
- result[resultPos] = -1;
- return result;
- }
- private static int CreateWindowEntry(int mult, int zeroes)
- {
- Debug.Assert(mult > 0);
- #if NETCOREAPP3_0_OR_GREATER
- int tz = BitOperations.TrailingZeroCount(mult);
- mult >>= tz;
- zeroes += tz;
- #else
- while ((mult & 1) == 0)
- {
- mult >>= 1;
- ++zeroes;
- }
- #endif
- return mult | (zeroes << 8);
- }
- /**
- * return w with w = x * x - w is assumed to have enough space.
- */
- private static int[] Square(
- int[] w,
- int[] x)
- {
- // 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...");
- ulong c;
- int wBase = w.Length - 1;
- for (int i = x.Length - 1; i > 0; --i)
- {
- ulong v = (uint)x[i];
- c = v * v + (uint)w[wBase];
- w[wBase] = (int)c;
- c >>= 32;
- for (int j = i - 1; j >= 0; --j)
- {
- ulong prod = v * (uint)x[j];
- c += ((uint)w[--wBase] & UIMASK) + ((uint)prod << 1);
- w[wBase] = (int)c;
- c = (c >> 32) + (prod >> 31);
- }
- c += (uint)w[--wBase];
- w[wBase] = (int)c;
- if (--wBase >= 0)
- {
- w[wBase] = (int)(c >> 32);
- }
- else
- {
- Debug.Assert((c >> 32) == 0);
- }
- wBase += i;
- }
- c = (uint)x[0];
- c = c * c + (uint)w[wBase];
- w[wBase] = (int)c;
- if (--wBase >= 0)
- {
- w[wBase] += (int)(c >> 32);
- }
- else
- {
- Debug.Assert((c >> 32) == 0);
- }
- return w;
- }
- /**
- * return x with x = y * z - x is assumed to have enough space.
- */
- private static int[] Multiply(int[] x, int[] y, int[] z)
- {
- int i = z.Length;
- if (i < 1)
- return x;
- int xBase = x.Length - y.Length;
- do
- {
- long a = z[--i] & IMASK;
- long val = 0;
- if (a != 0)
- {
- for (int j = y.Length - 1; j >= 0; j--)
- {
- val += a * (y[j] & IMASK) + (x[xBase + j] & IMASK);
-
- x[xBase + j] = (int)val;
-
- val = (long)((ulong)val >> 32);
- }
- }
- --xBase;
- if (xBase >= 0)
- {
- x[xBase] = (int)val;
- }
- else
- {
- Debug.Assert(val == 0);
- }
- }
- while (i > 0);
- return x;
- }
- /**
- * Calculate mQuote = -m^(-1) mod b with b = 2^32 (32 = word size)
- */
- private int GetMQuote()
- {
- Debug.Assert(this.sign > 0);
- int d = -magnitude[magnitude.Length - 1];
- Debug.Assert((d & 1) != 0);
- return (int)Raw.Mod.Inverse32((uint)d);
- }
- private static void MontgomeryReduce(int[] x, int[] m, uint mDash) // mDash = -m^(-1) mod b
- {
- // NOTE: Not a general purpose reduction (which would allow x up to twice the bitlength of m)
- Debug.Assert(x.Length == m.Length);
- int n = m.Length;
- for (int i = n - 1; i >= 0; --i)
- {
- uint x0 = (uint)x[n - 1];
- ulong t = x0 * mDash;
- ulong carry = t * (uint)m[n - 1] + x0;
- Debug.Assert((uint)carry == 0);
- carry >>= 32;
- for (int j = n - 2; j >= 0; --j)
- {
- carry += t * (uint)m[j] + (uint)x[j];
- x[j + 1] = (int)carry;
- carry >>= 32;
- }
- x[0] = (int)carry;
- Debug.Assert(carry >> 32 == 0);
- }
- if (CompareTo(0, x, 0, m) >= 0)
- {
- Subtract(0, x, 0, m);
- }
- }
- /**
- * 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>
- * <li> a should have length (n + 1) </li>
- * <li> b = 2^32, R = b^n </li>
- * <br/>
- * The result is put in x
- * <br/>
- * NOTE: the indices of x, y, m, a different in HAC and in Java
- */
- private static void MultiplyMonty(int[] a, int[] x, int[] y, int[] m, uint mDash, bool smallMontyModulus)
- // mDash = -m^(-1) mod b
- {
- int n = m.Length;
- if (n == 1)
- {
- x[0] = (int)MultiplyMontyNIsOne((uint)x[0], (uint)y[0], (uint)m[0], mDash);
- return;
- }
- uint y0 = (uint)y[n - 1];
- int aMax;
- {
- ulong xi = (uint)x[n - 1];
- ulong carry = xi * y0;
- ulong t = (uint)carry * mDash;
- ulong prod2 = t * (uint)m[n - 1];
- carry += (uint)prod2;
- Debug.Assert((uint)carry == 0);
- carry = (carry >> 32) + (prod2 >> 32);
- for (int j = n - 2; j >= 0; --j)
- {
- ulong prod1 = xi * (uint)y[j];
- prod2 = t * (uint)m[j];
- carry += (prod1 & UIMASK) + (uint)prod2;
- a[j + 2] = (int)carry;
- carry = (carry >> 32) + (prod1 >> 32) + (prod2 >> 32);
- }
- a[1] = (int)carry;
- aMax = (int)(carry >> 32);
- }
- for (int i = n - 2; i >= 0; --i)
- {
- uint a0 = (uint)a[n];
- ulong xi = (uint)x[i];
- ulong prod1 = xi * y0;
- ulong carry = (prod1 & UIMASK) + a0;
- ulong t = (uint)carry * mDash;
- ulong prod2 = t * (uint)m[n - 1];
- carry += (uint)prod2;
- Debug.Assert((uint)carry == 0);
- carry = (carry >> 32) + (prod1 >> 32) + (prod2 >> 32);
- for (int j = n - 2; j >= 0; --j)
- {
- prod1 = xi * (uint)y[j];
- prod2 = t * (uint)m[j];
- carry += (prod1 & UIMASK) + (uint)prod2 + (uint)a[j + 1];
- a[j + 2] = (int)carry;
- carry = (carry >> 32) + (prod1 >> 32) + (prod2 >> 32);
- }
- carry += (uint)aMax;
- a[1] = (int)carry;
- aMax = (int)(carry >> 32);
- }
- a[0] = aMax;
- if (!smallMontyModulus && CompareTo(0, a, 0, m) >= 0)
- {
- Subtract(0, a, 0, m);
- }
- Array.Copy(a, 1, x, 0, n);
- }
- private static void SquareMonty(int[] a, int[] x, int[] m, uint mDash, bool smallMontyModulus)
- // mDash = -m^(-1) mod b
- {
- int n = m.Length;
- if (n == 1)
- {
- uint xVal = (uint)x[0];
- x[0] = (int)MultiplyMontyNIsOne(xVal, xVal, (uint)m[0], mDash);
- return;
- }
- ulong x0 = (uint)x[n - 1];
- int aMax;
- {
- ulong carry = x0 * x0;
- ulong t = (uint)carry * mDash;
- ulong prod2 = t * (uint)m[n - 1];
- carry += (uint)prod2;
- Debug.Assert((uint)carry == 0);
- carry = (carry >> 32) + (prod2 >> 32);
- for (int j = n - 2; j >= 0; --j)
- {
- ulong prod1 = x0 * (uint)x[j];
- prod2 = t * (uint)m[j];
- carry += (prod2 & UIMASK) + ((uint)prod1 << 1);
- a[j + 2] = (int)carry;
- carry = (carry >> 32) + (prod1 >> 31) + (prod2 >> 32);
- }
- a[1] = (int)carry;
- aMax = (int)(carry >> 32);
- }
- for (int i = n - 2; i >= 0; --i)
- {
- uint a0 = (uint)a[n];
- ulong t = a0 * mDash;
- ulong carry = t * (uint)m[n - 1] + a0;
- Debug.Assert((uint)carry == 0);
- carry >>= 32;
- for (int j = n - 2; j > i; --j)
- {
- carry += t * (uint)m[j] + (uint)a[j + 1];
- a[j + 2] = (int)carry;
- carry >>= 32;
- }
- ulong xi = (uint)x[i];
- {
- ulong prod1 = xi * xi;
- ulong prod2 = t * (uint)m[i];
- carry += (prod1 & UIMASK) + (uint)prod2 + (uint)a[i + 1];
- a[i + 2] = (int)carry;
- carry = (carry >> 32) + (prod1 >> 32) + (prod2 >> 32);
- }
- for (int j = i - 1; j >= 0; --j)
- {
- ulong prod1 = xi * (uint)x[j];
- ulong prod2 = t * (uint)m[j];
- carry += (prod2 & UIMASK) + ((uint)prod1 << 1) + (uint)a[j + 1];
- a[j + 2] = (int)carry;
- carry = (carry >> 32) + (prod1 >> 31) + (prod2 >> 32);
- }
- carry += (uint)aMax;
- a[1] = (int)carry;
- aMax = (int)(carry >> 32);
- }
- a[0] = aMax;
- if (!smallMontyModulus && CompareTo(0, a, 0, m) >= 0)
- {
- Subtract(0, a, 0, m);
- }
- Array.Copy(a, 1, x, 0, n);
- }
- private static uint MultiplyMontyNIsOne(uint x, uint y, uint m, uint mDash)
- {
- ulong carry = (ulong)x * y;
- uint t = (uint)carry * mDash;
- ulong um = m;
- ulong prod2 = um * t;
- carry += (uint)prod2;
- Debug.Assert((uint)carry == 0);
- carry = (carry >> 32) + (prod2 >> 32);
- if (carry > um)
- {
- carry -= um;
- }
- Debug.Assert(carry < um);
- return (uint)carry;
- }
- public BigInteger Multiply(
- BigInteger val)
- {
- if (val == this)
- return Square();
- if ((sign & val.sign) == 0)
- return Zero;
- if (val.QuickPow2Check()) // val is power of two
- {
- BigInteger result = this.ShiftLeft(val.Abs().BitLength - 1);
- return val.sign > 0 ? result : result.Negate();
- }
- if (this.QuickPow2Check()) // this is power of two
- {
- BigInteger result = val.ShiftLeft(this.Abs().BitLength - 1);
- return this.sign > 0 ? result : result.Negate();
- }
- int resLength = magnitude.Length + val.magnitude.Length;
- int[] res = new int[resLength];
- Multiply(res, this.magnitude, val.magnitude);
- int resSign = sign ^ val.sign ^ 1;
- return new BigInteger(resSign, res, true);
- }
- public BigInteger Square()
- {
- if (sign == 0)
- return Zero;
- if (this.QuickPow2Check())
- return ShiftLeft(Abs().BitLength - 1);
- int resLength = magnitude.Length << 1;
- if ((uint)magnitude[0] >> 16 == 0)
- --resLength;
- int[] res = new int[resLength];
- Square(res, magnitude);
- return new BigInteger(1, res, false);
- }
- public BigInteger Negate()
- {
- if (sign == 0)
- return this;
- return new BigInteger(-sign, magnitude, false);
- }
- public BigInteger NextProbablePrime()
- {
- if (sign < 0)
- throw new ArithmeticException("Cannot be called on value < 0");
- if (CompareTo(Two) < 0)
- return Two;
- BigInteger n = Inc().SetBit(0);
- while (!n.CheckProbablePrime(100, SecureRandom.ArbitraryRandom, false))
- {
- n = n.Add(Two);
- }
- return n;
- }
- public BigInteger Not()
- {
- return Inc().Negate();
- }
- public BigInteger Pow(int exp)
- {
- if (exp <= 0)
- {
- if (exp < 0)
- throw new ArithmeticException("Negative exponent");
- return One;
- }
- if (sign == 0)
- {
- return this;
- }
- if (QuickPow2Check())
- {
- long powOf2 = (long)exp * (BitLength - 1);
- if (powOf2 > int.MaxValue)
- {
- throw new ArithmeticException("Result too large");
- }
- return One.ShiftLeft((int)powOf2);
- }
- BigInteger y = One;
- BigInteger z = this;
- for (;;)
- {
- if ((exp & 0x1) == 1)
- {
- y = y.Multiply(z);
- }
- exp >>= 1;
- if (exp == 0) break;
- z = z.Multiply(z);
- }
- return y;
- }
- public static BigInteger ProbablePrime(
- int bitLength,
- Random random)
- {
- return new BigInteger(bitLength, 100, random);
- }
- private int Remainder(
- int m)
- {
- Debug.Assert(m > 0);
- long acc = 0;
- for (int pos = 0; pos < magnitude.Length; ++pos)
- {
- long posVal = (uint) magnitude[pos];
- acc = (acc << 32 | posVal) % m;
- }
- return (int) acc;
- }
- /**
- * return x = x % y - done in place (y value preserved)
- */
- private static int[] Remainder(
- int[] x,
- int[] y)
- {
- int xStart = 0;
- while (xStart < x.Length && x[xStart] == 0)
- {
- ++xStart;
- }
- int yStart = 0;
- while (yStart < y.Length && y[yStart] == 0)
- {
- ++yStart;
- }
- Debug.Assert(yStart < y.Length);
- int xyCmp = CompareNoLeadingZeroes(xStart, x, yStart, y);
- if (xyCmp > 0)
- {
- int yBitLength = CalcBitLength(1, yStart, y);
- int xBitLength = CalcBitLength(1, xStart, x);
- int shift = xBitLength - yBitLength;
- int[] c;
- int cStart = 0;
- int cBitLength = yBitLength;
- if (shift > 0)
- {
- c = ShiftLeft(y, shift);
- cBitLength += shift;
- Debug.Assert(c[0] != 0);
- }
- else
- {
- int len = y.Length - yStart;
- c = new int[len];
- Array.Copy(y, yStart, c, 0, len);
- }
- for (;;)
- {
- if (cBitLength < xBitLength
- || CompareNoLeadingZeroes(xStart, x, cStart, c) >= 0)
- {
- Subtract(xStart, x, cStart, c);
- while (x[xStart] == 0)
- {
- if (++xStart == x.Length)
- return x;
- }
- //xBitLength = CalcBitLength(xStart, x);
- xBitLength = 32 * (x.Length - xStart - 1) + BitLen(x[xStart]);
- if (xBitLength <= yBitLength)
- {
- if (xBitLength < yBitLength)
- return x;
- xyCmp = CompareNoLeadingZeroes(xStart, x, yStart, y);
- if (xyCmp <= 0)
- break;
- }
- }
- shift = cBitLength - xBitLength;
- // NB: The case where c[cStart] is 1-bit is harmless
- if (shift == 1)
- {
- uint firstC = (uint) c[cStart] >> 1;
- uint firstX = (uint) x[xStart];
- if (firstC > firstX)
- ++shift;
- }
- if (shift < 2)
- {
- ShiftRightOneInPlace(cStart, c);
- --cBitLength;
- }
- else
- {
- ShiftRightInPlace(cStart, c, shift);
- cBitLength -= shift;
- }
- //cStart = c.Length - ((cBitLength + 31) / 32);
- while (c[cStart] == 0)
- {
- ++cStart;
- }
- }
- }
- if (xyCmp == 0)
- {
- Array.Clear(x, xStart, x.Length - xStart);
- }
- return x;
- }
- public BigInteger Remainder(
- BigInteger n)
- {
- if (n.sign == 0)
- throw new ArithmeticException("Division by zero error");
- if (this.sign == 0)
- return Zero;
- // For small values, use fast remainder method
- if (n.magnitude.Length == 1)
- {
- int val = n.magnitude[0];
- if (val > 0)
- {
- if (val == 1)
- return Zero;
- // TODO Make this func work on uint, and handle val == 1?
- int rem = Remainder(val);
- return rem == 0
- ? Zero
- : new BigInteger(sign, new int[]{ rem }, false);
- }
- }
- if (CompareNoLeadingZeroes(0, magnitude, 0, n.magnitude) < 0)
- return this;
- int[] result;
- if (n.QuickPow2Check()) // n is power of two
- {
- // TODO Move before small values branch above?
- result = LastNBits(n.Abs().BitLength - 1);
- }
- else
- {
- result = (int[]) this.magnitude.Clone();
- result = Remainder(result, n.magnitude);
- }
- return new BigInteger(sign, result, true);
- }
- private int[] LastNBits(
- int n)
- {
- if (n < 1)
- return ZeroMagnitude;
- int numWords = (n + BitsPerInt - 1) / BitsPerInt;
- numWords = System.Math.Min(numWords, this.magnitude.Length);
- int[] result = new int[numWords];
- Array.Copy(this.magnitude, this.magnitude.Length - numWords, result, 0, numWords);
- int excessBits = (numWords << 5) - n;
- if (excessBits > 0)
- {
- result[0] &= (int)(uint.MaxValue >> excessBits);
- }
- return result;
- }
- private BigInteger DivideWords(int w)
- {
- Debug.Assert(w >= 0);
- int n = magnitude.Length;
- if (w >= n)
- return Zero;
- int[] mag = new int[n - w];
- Array.Copy(magnitude, 0, mag, 0, n - w);
- return new BigInteger(sign, mag, false);
- }
- private BigInteger RemainderWords(int w)
- {
- Debug.Assert(w >= 0);
- int n = magnitude.Length;
- if (w >= n)
- return this;
- int[] mag = new int[w];
- Array.Copy(magnitude, n - w, mag, 0, w);
- return new BigInteger(sign, mag, false);
- }
- /**
- * do a left shift - this returns a new array.
- */
- private static int[] ShiftLeft(
- int[] mag,
- int n)
- {
- int nInts = (int)((uint)n >> 5);
- int nBits = n & 0x1f;
- int magLen = mag.Length;
- int[] newMag;
- if (nBits == 0)
- {
- newMag = new int[magLen + nInts];
- mag.CopyTo(newMag, 0);
- }
- else
- {
- int i = 0;
- int nBits2 = 32 - nBits;
- int highBits = (int)((uint)mag[0] >> nBits2);
- if (highBits != 0)
- {
- newMag = new int[magLen + nInts + 1];
- newMag[i++] = highBits;
- }
- else
- {
- newMag = new int[magLen + nInts];
- }
- int m = mag[0];
- for (int j = 0; j < magLen - 1; j++)
- {
- int next = mag[j + 1];
- newMag[i++] = (m << nBits) | (int)((uint)next >> nBits2);
- m = next;
- }
- newMag[i] = mag[magLen - 1] << nBits;
- }
- return newMag;
- }
- private static int ShiftLeftOneInPlace(int[] x, int carry)
- {
- Debug.Assert(carry == 0 || carry == 1);
- int pos = x.Length;
- while (--pos >= 0)
- {
- uint val = (uint)x[pos];
- x[pos] = (int)(val << 1) | carry;
- carry = (int)(val >> 31);
- }
- return carry;
- }
- public BigInteger ShiftLeft(
- int n)
- {
- if (sign == 0 || magnitude.Length == 0)
- return Zero;
- if (n == 0)
- return this;
- if (n < 0)
- return ShiftRight(-n);
- BigInteger result = new BigInteger(sign, ShiftLeft(magnitude, n), true);
- if (this.nBits != -1)
- {
- result.nBits = sign > 0
- ? this.nBits
- : this.nBits + n;
- }
- if (this.nBitLength != -1)
- {
- result.nBitLength = this.nBitLength + n;
- }
- return result;
- }
- /**
- * do a right shift - this does it in place.
- */
- private static void ShiftRightInPlace(
- int start,
- int[] mag,
- int n)
- {
- int nInts = (int)((uint)n >> 5) + start;
- int nBits = n & 0x1f;
- int magEnd = mag.Length - 1;
- if (nInts != start)
- {
- int delta = (nInts - start);
- for (int i = magEnd; i >= nInts; i--)
- {
- mag[i] = mag[i - delta];
- }
- for (int i = nInts - 1; i >= start; i--)
- {
- mag[i] = 0;
- }
- }
- if (nBits != 0)
- {
- int nBits2 = 32 - nBits;
- int m = mag[magEnd];
- for (int i = magEnd; i > nInts; --i)
- {
- int next = mag[i - 1];
- mag[i] = (int)((uint)m >> nBits) | (next << nBits2);
- m = next;
- }
- mag[nInts] = (int)((uint)mag[nInts] >> nBits);
- }
- }
- /**
- * do a right shift by one - this does it in place.
- */
- private static void ShiftRightOneInPlace(
- int start,
- int[] mag)
- {
- int i = mag.Length;
- int m = mag[i - 1];
- while (--i > start)
- {
- int next = mag[i - 1];
- mag[i] = ((int)((uint)m >> 1)) | (next << 31);
- m = next;
- }
- mag[start] = (int)((uint)mag[start] >> 1);
- }
- public BigInteger ShiftRight(
- int n)
- {
- if (n == 0)
- return this;
- if (n < 0)
- return ShiftLeft(-n);
- if (n >= BitLength)
- return (this.sign < 0 ? One.Negate() : Zero);
- // int[] res = (int[]) this.magnitude.Clone();
- //
- // ShiftRightInPlace(0, res, n);
- //
- // return new BigInteger(this.sign, res, true);
- int resultLength = (BitLength - n + 31) >> 5;
- int[] res = new int[resultLength];
- int numInts = n >> 5;
- int numBits = n & 31;
- if (numBits == 0)
- {
- Array.Copy(this.magnitude, 0, res, 0, res.Length);
- }
- else
- {
- int numBits2 = 32 - numBits;
- int magPos = this.magnitude.Length - 1 - numInts;
- for (int i = resultLength - 1; i >= 0; --i)
- {
- res[i] = (int)((uint) this.magnitude[magPos--] >> numBits);
- if (magPos >= 0)
- {
- res[i] |= this.magnitude[magPos] << numBits2;
- }
- }
- }
- Debug.Assert(res[0] != 0);
- return new BigInteger(this.sign, res, false);
- }
- public int SignValue
- {
- get { return sign; }
- }
- /**
- * returns x = x - y - we assume x is >= y
- */
- private static int[] Subtract(
- int xStart,
- int[] x,
- int yStart,
- int[] y)
- {
- Debug.Assert(yStart < y.Length);
- Debug.Assert(x.Length - xStart >= y.Length - yStart);
- int iT = x.Length;
- int iV = y.Length;
- long m;
- int borrow = 0;
- do
- {
- m = (x[--iT] & IMASK) - (y[--iV] & IMASK) + borrow;
- x[iT] = (int) m;
- // borrow = (m < 0) ? -1 : 0;
- borrow = (int)(m >> 63);
- }
- while (iV > yStart);
- if (borrow != 0)
- {
- while (--x[--iT] == -1)
- {
- }
- }
- return x;
- }
- public BigInteger Subtract(
- BigInteger n)
- {
- if (n.sign == 0)
- return this;
- if (this.sign == 0)
- return n.Negate();
- if (this.sign != n.sign)
- return Add(n.Negate());
- int compare = CompareNoLeadingZeroes(0, magnitude, 0, n.magnitude);
- if (compare == 0)
- return Zero;
- BigInteger bigun, lilun;
- if (compare < 0)
- {
- bigun = n;
- lilun = this;
- }
- else
- {
- bigun = this;
- lilun = n;
- }
- return new BigInteger(this.sign * compare, doSubBigLil(bigun.magnitude, lilun.magnitude), true);
- }
- private static int[] doSubBigLil(
- int[] bigMag,
- int[] lilMag)
- {
- int[] res = (int[]) bigMag.Clone();
- return Subtract(0, res, 0, lilMag);
- }
- public int GetLengthofByteArray()
- {
- return GetByteLength(BitLength + 1);
- }
- public int GetLengthofByteArrayUnsigned()
- {
- return GetByteLength(sign < 0 ? BitLength + 1 : BitLength);
- }
- public byte[] ToByteArray()
- {
- return ToByteArray(false);
- }
- #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || _UNITY_2021_2_OR_NEWER_
- public void ToByteArray(Span<byte> output)
- {
- ToByteArray(false, output);
- }
- #endif
- public byte[] ToByteArrayUnsigned()
- {
- return ToByteArray(true);
- }
- #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || _UNITY_2021_2_OR_NEWER_
- public void ToByteArrayUnsigned(Span<byte> output)
- {
- ToByteArray(true, output);
- }
- #endif
- private byte[] ToByteArray(bool unsigned)
- {
- if (sign == 0)
- return unsigned ? ZeroEncoding : new byte[1];
- int nBits = (unsigned && sign > 0)
- ? BitLength
- : BitLength + 1;
- int nBytes = GetByteLength(nBits);
- byte[] bytes = new byte[nBytes];
- int magIndex = magnitude.Length;
- int bytesIndex = bytes.Length;
- if (sign > 0)
- {
- while (magIndex > 1)
- {
- uint mag = (uint) magnitude[--magIndex];
- bytesIndex -= 4;
- Pack.UInt32_To_BE(mag, bytes, bytesIndex);
- }
- uint lastMag = (uint) magnitude[0];
- while (lastMag > byte.MaxValue)
- {
- bytes[--bytesIndex] = (byte) lastMag;
- lastMag >>= 8;
- }
- bytes[--bytesIndex] = (byte) lastMag;
- }
- else // sign < 0
- {
- bool carry = true;
- while (magIndex > 1)
- {
- uint mag = ~((uint) magnitude[--magIndex]);
- if (carry)
- {
- carry = (++mag == uint.MinValue);
- }
- bytesIndex -= 4;
- Pack.UInt32_To_BE(mag, bytes, bytesIndex);
- }
- uint lastMag = (uint) magnitude[0];
- if (carry)
- {
- // Never wraps because magnitude[0] != 0
- --lastMag;
- }
- while (lastMag > byte.MaxValue)
- {
- bytes[--bytesIndex] = (byte) ~lastMag;
- lastMag >>= 8;
- }
- bytes[--bytesIndex] = (byte) ~lastMag;
- if (bytesIndex > 0)
- {
- bytes[--bytesIndex] = byte.MaxValue;
- }
- }
- return bytes;
- }
- #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || _UNITY_2021_2_OR_NEWER_
- private void ToByteArray(bool unsigned, Span<byte> output)
- {
- if (sign == 0)
- {
- if (!unsigned)
- {
- output[0] = 0;
- }
- return;
- }
- int nBits = (unsigned && sign > 0) ? BitLength : BitLength + 1;
- int nBytes = GetByteLength(nBits);
- if (nBytes > output.Length)
- throw new ArgumentException("insufficient space", nameof(output));
- int magIndex = magnitude.Length;
- int bytesIndex = nBytes;
- if (sign > 0)
- {
- while (magIndex > 1)
- {
- uint mag = (uint) magnitude[--magIndex];
- bytesIndex -= 4;
- Pack.UInt32_To_BE(mag, output[bytesIndex..]);
- }
- uint lastMag = (uint)magnitude[0];
- while (lastMag > byte.MaxValue)
- {
- output[--bytesIndex] = (byte)lastMag;
- lastMag >>= 8;
- }
- output[--bytesIndex] = (byte)lastMag;
- }
- else // sign < 0
- {
- bool carry = true;
- while (magIndex > 1)
- {
- uint mag = ~((uint)magnitude[--magIndex]);
- if (carry)
- {
- carry = (++mag == uint.MinValue);
- }
- bytesIndex -= 4;
- Pack.UInt32_To_BE(mag, output[bytesIndex..]);
- }
- uint lastMag = (uint)magnitude[0];
- if (carry)
- {
- // Never wraps because magnitude[0] != 0
- --lastMag;
- }
- while (lastMag > byte.MaxValue)
- {
- output[--bytesIndex] = (byte)~lastMag;
- lastMag >>= 8;
- }
- output[--bytesIndex] = (byte)~lastMag;
- if (bytesIndex > 0)
- {
- output[--bytesIndex] = byte.MaxValue;
- }
- }
- }
- #endif
- public override string ToString()
- {
- return ToString(10);
- }
- public string ToString(int radix)
- {
- // TODO Make this method work for other radices (ideally 2 <= radix <= 36 as in Java)
- switch (radix)
- {
- case 2:
- case 8:
- case 10:
- case 16:
- break;
- default:
- throw new FormatException("Only bases 2, 8, 10, 16 are allowed");
- }
- // NB: Can only happen to internally managed instances
- if (magnitude == null)
- return "null";
- if (sign == 0)
- return "0";
- // NOTE: This *should* be unnecessary, since the magnitude *should* never have leading zero digits
- int firstNonZero = 0;
- while (firstNonZero < magnitude.Length)
- {
- if (magnitude[firstNonZero] != 0)
- {
- break;
- }
- ++firstNonZero;
- }
- if (firstNonZero == magnitude.Length)
- {
- return "0";
- }
- StringBuilder sb = new StringBuilder();
- if (sign == -1)
- {
- sb.Append('-');
- }
- switch (radix)
- {
- case 2:
- {
- int pos = firstNonZero;
- sb.Append(Convert.ToString(magnitude[pos], 2));
- while (++pos < magnitude.Length)
- {
- AppendZeroExtendedString(sb, Convert.ToString(magnitude[pos], 2), 32);
- }
- break;
- }
- case 8:
- {
- int mask = (1 << 30) - 1;
- BigInteger u = this.Abs();
- int bits = u.BitLength;
- var S = new List<string>();
- while (bits > 30)
- {
- S.Add(Convert.ToString(u.IntValue & mask, 8));
- u = u.ShiftRight(30);
- bits -= 30;
- }
- sb.Append(Convert.ToString(u.IntValue, 8));
- for (int i = S.Count - 1; i >= 0; --i)
- {
- AppendZeroExtendedString(sb, S[i], 10);
- }
- break;
- }
- case 16:
- {
- int pos = firstNonZero;
- sb.Append(Convert.ToString(magnitude[pos], 16));
- while (++pos < magnitude.Length)
- {
- AppendZeroExtendedString(sb, Convert.ToString(magnitude[pos], 16), 8);
- }
- break;
- }
- // TODO This could work for other radices if there is an alternative to Convert.ToString method
- //default:
- case 10:
- {
- BigInteger q = this.Abs();
- if (q.BitLength < 64)
- {
- sb.Append(Convert.ToString(q.LongValue, radix));
- break;
- }
- // TODO Could cache the moduli for each radix (soft reference?)
- var moduli = new List<BigInteger>();
- BigInteger R = ValueOf(radix);
- while (R.CompareTo(q) <= 0)
- {
- moduli.Add(R);
- R = R.Square();
- }
- int scale = moduli.Count;
- sb.EnsureCapacity(sb.Length + (1 << scale));
- ToString(sb, radix, moduli, scale, q);
- break;
- }
- }
- return sb.ToString();
- }
- private static void ToString(StringBuilder sb, int radix, IList<BigInteger> moduli, int scale, BigInteger pos)
- {
- if (pos.BitLength < 64)
- {
- string s = Convert.ToString(pos.LongValue, radix);
- if (sb.Length > 1 || (sb.Length == 1 && sb[0] != '-'))
- {
- AppendZeroExtendedString(sb, s, 1 << scale);
- }
- else if (pos.SignValue != 0)
- {
- sb.Append(s);
- }
- return;
- }
- BigInteger[] qr = pos.DivideAndRemainder(moduli[--scale]);
- ToString(sb, radix, moduli, scale, qr[0]);
- ToString(sb, radix, moduli, scale, qr[1]);
- }
- private static void AppendZeroExtendedString(StringBuilder sb, string s, int minLength)
- {
- for (int len = s.Length; len < minLength; ++len)
- {
- sb.Append('0');
- }
- sb.Append(s);
- }
- private static BigInteger CreateUValueOf(
- ulong value)
- {
- int msw = (int)(value >> 32);
- int lsw = (int)value;
- if (msw != 0)
- return new BigInteger(1, new int[] { msw, lsw }, false);
- if (lsw != 0)
- {
- BigInteger n = new BigInteger(1, new int[] { lsw }, false);
- // Check for a power of two
- if ((lsw & -lsw) == lsw)
- {
- n.nBits = 1;
- }
- return n;
- }
- return Zero;
- }
- private static BigInteger CreateValueOf(
- long value)
- {
- if (value < 0)
- {
- if (value == long.MinValue)
- return CreateValueOf(~value).Not();
- return CreateValueOf(-value).Negate();
- }
- return CreateUValueOf((ulong)value);
- }
- public static BigInteger ValueOf(
- long value)
- {
- if (value >= 0 && value < SMALL_CONSTANTS.Length)
- {
- return SMALL_CONSTANTS[value];
- }
- return CreateValueOf(value);
- }
- public int GetLowestSetBit()
- {
- if (this.sign == 0)
- return -1;
- return GetLowestSetBitMaskFirst(-1);
- }
- private int GetLowestSetBitMaskFirst(int firstWordMask)
- {
- int w = magnitude.Length, offset = 0;
- uint word = (uint)(magnitude[--w] & firstWordMask);
- Debug.Assert(magnitude[0] != 0);
- while (word == 0)
- {
- word = (uint)magnitude[--w];
- offset += 32;
- }
- #if NETCOREAPP3_0_OR_GREATER
- offset += BitOperations.TrailingZeroCount(word);
- #else
- while ((word & 0xFF) == 0)
- {
- word >>= 8;
- offset += 8;
- }
- while ((word & 1) == 0)
- {
- word >>= 1;
- ++offset;
- }
- #endif
- return offset;
- }
- public bool TestBit(
- int n)
- {
- if (n < 0)
- throw new ArithmeticException("Bit position must not be negative");
- if (sign < 0)
- return !Not().TestBit(n);
- int wordNum = n / 32;
- if (wordNum >= magnitude.Length)
- return false;
- int word = magnitude[magnitude.Length - 1 - wordNum];
- return ((word >> (n % 32)) & 1) > 0;
- }
- public BigInteger Or(
- BigInteger value)
- {
- if (this.sign == 0)
- return value;
- if (value.sign == 0)
- return this;
- int[] aMag = this.sign > 0
- ? this.magnitude
- : Add(One).magnitude;
- int[] bMag = value.sign > 0
- ? value.magnitude
- : value.Add(One).magnitude;
- bool resultNeg = sign < 0 || value.sign < 0;
- int resultLength = System.Math.Max(aMag.Length, bMag.Length);
- int[] resultMag = new int[resultLength];
- int aStart = resultMag.Length - aMag.Length;
- int bStart = resultMag.Length - bMag.Length;
- for (int i = 0; i < resultMag.Length; ++i)
- {
- int aWord = i >= aStart ? aMag[i - aStart] : 0;
- int bWord = i >= bStart ? bMag[i - bStart] : 0;
- if (this.sign < 0)
- {
- aWord = ~aWord;
- }
- if (value.sign < 0)
- {
- bWord = ~bWord;
- }
- resultMag[i] = aWord | bWord;
- if (resultNeg)
- {
- resultMag[i] = ~resultMag[i];
- }
- }
- BigInteger result = new BigInteger(1, resultMag, true);
- // TODO Optimise this case
- if (resultNeg)
- {
- result = result.Not();
- }
- return result;
- }
- public BigInteger Xor(
- BigInteger value)
- {
- if (this.sign == 0)
- return value;
- if (value.sign == 0)
- return this;
- int[] aMag = this.sign > 0
- ? this.magnitude
- : Add(One).magnitude;
- int[] bMag = value.sign > 0
- ? value.magnitude
- : value.Add(One).magnitude;
- // TODO Can just replace with sign != value.sign?
- bool resultNeg = (sign < 0 && value.sign >= 0) || (sign >= 0 && value.sign < 0);
- int resultLength = System.Math.Max(aMag.Length, bMag.Length);
- int[] resultMag = new int[resultLength];
- int aStart = resultMag.Length - aMag.Length;
- int bStart = resultMag.Length - bMag.Length;
- for (int i = 0; i < resultMag.Length; ++i)
- {
- int aWord = i >= aStart ? aMag[i - aStart] : 0;
- int bWord = i >= bStart ? bMag[i - bStart] : 0;
- if (this.sign < 0)
- {
- aWord = ~aWord;
- }
- if (value.sign < 0)
- {
- bWord = ~bWord;
- }
- resultMag[i] = aWord ^ bWord;
- if (resultNeg)
- {
- resultMag[i] = ~resultMag[i];
- }
- }
- BigInteger result = new BigInteger(1, resultMag, true);
- // TODO Optimise this case
- if (resultNeg)
- {
- result = result.Not();
- }
- return result;
- }
- public BigInteger SetBit(
- int n)
- {
- if (n < 0)
- throw new ArithmeticException("Bit address less than zero");
- if (TestBit(n))
- return this;
- // TODO Handle negative values and zero
- if (sign > 0 && n < (BitLength - 1))
- return FlipExistingBit(n);
- return Or(One.ShiftLeft(n));
- }
- public BigInteger ClearBit(
- int n)
- {
- if (n < 0)
- throw new ArithmeticException("Bit address less than zero");
- if (!TestBit(n))
- return this;
- // TODO Handle negative values
- if (sign > 0 && n < (BitLength - 1))
- return FlipExistingBit(n);
- return AndNot(One.ShiftLeft(n));
- }
- public BigInteger FlipBit(
- int n)
- {
- if (n < 0)
- throw new ArithmeticException("Bit address less than zero");
- // TODO Handle negative values and zero
- if (sign > 0 && n < (BitLength - 1))
- return FlipExistingBit(n);
- return Xor(One.ShiftLeft(n));
- }
- private BigInteger FlipExistingBit(
- int n)
- {
- Debug.Assert(sign > 0);
- Debug.Assert(n >= 0);
- Debug.Assert(n < BitLength - 1);
- int[] mag = (int[]) this.magnitude.Clone();
- mag[mag.Length - 1 - (n >> 5)] ^= (1 << (n & 31)); // Flip bit
- return new BigInteger(this.sign, mag, false);
- }
- }
- }
- #pragma warning restore
- #endif
|