1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00

math.big: add mod_inverse and improve big_mod_pow to allow for large exponents and moduli (#18461)

This commit is contained in:
phoebe 2023-06-19 16:59:49 +02:00 committed by GitHub
parent 396d46d9ca
commit a3f24caffc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 599 additions and 63 deletions

View File

@ -289,38 +289,74 @@ fn test_mod_exponentiation() {
assert b.mod_pow(413, div) == a
}
fn test_big_mod_exponentiation_1() {
a := big.integer_from_int(23)
b := big.integer_from_int(35)
c := big.integer_from_int(4205)
result := big.integer_from_int(552)
assert a.big_mod_pow(b, c) == result
struct BigModPowTest {
base string
exponent string
modulus string
expected string
}
fn test_big_mod_exponentiation_2() {
a := big.integer_from_string('2222589987119231759186196754430278233855361024') or {
panic('Could not read big integer')
}
b := big.integer_from_string('3104719823194124242') or { panic('Could not read big integer') }
c := big.integer_from_string('15121308410741') or { panic('Could not read big integer') }
result := big.integer_from_string('487881863537') or { panic('Could not read big integer') }
assert a.big_mod_pow(b, c) == result
}
const big_mod_pow_test_data = [
// vfmt off
BigModPowTest{ // passed to mod_pow
'23',
'35',
'4205',
'552'
},
BigModPowTest{
'5155371529688',
'2791323022555160232601405723625177570767523893639864538140315412',
'108959927459825236754563833',
'26860526814751021488886966'
},
BigModPowTest{ // odd modulus
'352374589237450928347609812740958719304509123759871239856523745782375908723095729758275893947985713250128357912349123412939358823582385385198351236046127834612374812370491327508137250913279785120956123875610235871239857198203659081236598012735981327096129836712397538257324587324658973246586212305713209851290386517823650983',
'1435987139846732486843289483294829493285238539385476982375980650172394182703846128975612083751298035612365812378908579834576456739458768754674674758467957697513267415734673649713598712634987126359872685236563875',
'235091287508475298347528357901372598012305123512513252139683276908769284375274983274732895287478365817326581273509823651087861235876123563725193512827341395182375612384723587131912725187352562171235812387132578235385239913578132684794719844871326571632561325617256983275689175687132487134894717895941563769587165871727358791326578126587261589732165781623578921653625871256781326587132658716237561235612783569812358791263985688921356634756374561398756298576128463875627',
'169366899917096971139137080261692248176119100321982279129907315595573960531869689311776921667033660828498254917762241531493510090131310371752611041591194730984721766392649610729748330695093443476931010397820703902902374473806912248240019857777647140275706106146415293419050004306619925031697942412075960435433660980502714238024766862370671258678169869169308956145487178274009104771385352022837969419172440632584754050020898915411115587200113298960058827089497449758704',
},
BigModPowTest{
'65963856903485603485069234860923480925798172358172309571298347102836578126398512837409812375712637895612379856123981237510298356120347129803401236571623978561287347129837563453245983475983457439573985398456987356198236481727340813259182735619827356189723658763578623842342348791856178236598273498213492641265929375983589324658972364587869871263587612387568767345727346273647235738786247865198746132879461234613284823467',
'83272598179813257612837472873648237598405840629839475914921364871236813258573298457912734897123942134273981',
'5839857294085157278513295172390857198203571235213752396329429342385198326512374982374982394818327590816263059612397512983479812378951235123571239857908674389573485791835127834617823648791263587321501273958734987520983475818586128374612837589734985729073459081628387561982736547958729875923652356138756183576',
'1473628912328925119498300555459646092229919432628304743927027840523966896206312866878166443381090567655363186687840805386391819767096022910509388879763843632740700147538366282034781700814905320520871339523971198789410048087451530293781098724024347130773477767285944506944257502250353223975013799044669645147',
},
BigModPowTest{
'113242346235324852305823906832570234458325884382848882352385183957109823579028553482572308468203945823946234096234056990567506978059607985823049523458273598234750329857',
'80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000',
'538232475982347092375235252304678234670293486732980467394932151374571938467459586739087429813752353459823475982375983259823495510986571430996238476587342658172851235761398456398765813459801238751782351252542389712789568712342749837482748292340120120350125012352859821657823501275012365123985761983576123561273561257632958127659327160124712350123571029356123512507123598321797',
'192406008638594029999856291470760872362212741932343638540342189789173751505083836385843995643278520411152869906156437055678588013127671381619800101872065097151880787029771615331116606406595932983669815757450573569058422413443800383057849205750667577751024330669200452034408252515262931175662782786664172617789499914619948520343146045783354828154425927051367644302499369000252',
},
BigModPowTest{ // even modulus
'235823052395732458137502345873250',
'9247324572804102889565555777311914057954687482673431192869682151395651003606366864848904841770165182604035932529621174486515688424932060959148379649412557',
'2176617445861743577319100889181907668374255538511144643224689886235383840957210909013086056401571399717235807266581649606472148410291413364152197364477180887395655483738115072677402235101762521901569820740293149529620419333266262073471054548368736039519702486226506248861060256971802984953561121442680157668000761429988222457090413873973970171927093992114751765168063614761119615476233422096442783117971236371647333871414335895773474667308967050807005509320424799678417036867928316761272274230314067548291133582479583061439577559347101961771406173684378522703483495337037655006751328447510550299250924469288818',
'442997670902441289693502035236411859724060788065895656400579052337406446773758010436855122951259016429941998670112046510440662262181776245572088822784133641469508278250883828352296420961829921453124482851450238472747959697964344812370952273954391788494014188845640003786259215718720844436373044245757220429613176387487778233231542432645946351180509817097194411903946161272789482180797502735809791321387092632573236334305080001390892058454801700346356574718281589228939135660037060121182304974907075601193595994210348704718150369101358547875357900995290428579291079564736470284970163062216850888677989344123412'
},
BigModPowTest{
'5155342534532472457235424353715296885321784212092346234575235718572938457284759829789708703754094283682345782309123940810923850923745723498672398459023845028309402347698798128209480234598716824503042159',
'86088201503667039039649712985497870124991029230637396538140315482910296196688861780721773488400937149055855947456947824680518799310618149812585881185273945728945238450238465982768132749812308932579342985729345798328459832591982374981237590923882894732852358383128938192888912389148132163716923461512177401900495710673973552425181964932538140315421936569702910921834517138450159290932430254268769414',
'274591906405224388599271723580726658164960647214841029141336415219736447718088739565548373811507267740223510760319632557286907774120057322163752385728943578236484780326508234652347012734098132747829056238742677853836742172732148487951998402235107603196866575250296113164460906849287604912497386435248807205228608',
'191409711082233170599206818399072245570776992384487887400529042633340865718475272702984694979757086140971619519330041885966232600204343618098862571914303534164078578922423233100444505069197147657365390879382972696958855409999020160689093198793125749417593529720182526801136320146027275209623807723638007207345057',
},
BigModPowTest{ // power of 2 modulus
'853475230582304956623462734587234857',
'583752847502934572695871320598123057810835791832765601237490813250912360591237591247132543095792347598327957137481023974819237887128577123758127912735720912735708362178561027835610235610256231201472309873219800321951',
'31195165372897259196222538898096203590151924108450147950531565441852619837316692843188389598728651769482088968838700984268947453885587967878549286444999755742573423371025356539077075265986419171772426279084559025861175301940492273427120221755816136975739916983004778387946699939545354293487098252428954036286183995782377175227121587657233553706589448547148066273280603243167958729707736664649187444136702017299877489729451997277875868782399735511520086969969766278182145454186690598629675562422923132555707758646587702550600894625696538109646366308973392363200122154242784576162149305816215109893613161331026672647000825615987247035266514313689413563779184515427920269935280569035788081552413007563772309295149800172031645681720569680154349893907395864528243629654386620034655445226295834594630792819545156798270599481573436039129275439653984521135652249263653985326577886990615665734998585216581730937090703518997669223802429711292740491797911117308280939507973715877108492303860661291987529284719391551256912380499409630332506454532263266457209921483705507359152839264852808182519011100934922492651373859423833024010283468753147686188675294998119637462200763443029190704825719342806119404339670408160210011918981038977425180213726646978883378058838510330816291941879581568740273684084511318422175006728346276489384220596694727036836687670632486602655240593463885077059375085482211864761344849868123074687509143827139683659102930877963676911995751113159944160296419825178911962487549670296207457410515598040046860567719116506974858703739531721991704589155513182996455827177472',
'20080128881481836026329919458482291336427826856257996902940216961274769492432457342329585911526680598599706497937330675336231322550089070961997878231160797014417182095610964306078005177657705895303701167263611016504813896879268670353690809857529479048652197026092060293580162938995900771157020773980149060390600886988165389386800313399935681668574561849644795370126640258861886083152431680309682414362667647047408205246634496700184520404072535696087062725321498879508195864728319264953502905783599235208616928912295007582161378604427602444176983900856363236858555001132922259491209136145654862306503211818341793436738181575298025051779368026867674815572620689517665845691581156037531328681002192885908572782500210185856071870996928958700199226442991667291661898788475465881534872952976564959204125435567408766407069080824764398534937188392006557445009391997597405999602710062336419706104598663078108578494090878260551511868925451048198114479011315931259263368212342695453474607592164864833976245439378166385649596428707473508482940426102862136582304433403471613967149235623865180698593404828164563801111816849132293956996556247415009648932020221786934682827799748481777622180801590275002765776928805756187584952776044614940158088391767782343033313716059721086499569092199761880797791493764006487948292742803823944731896556184944138299575510183812680359579022267096795084742403276965131310267236257021618824374001979653996305168583849734973984410291953747451176667816227487401602863864660642232048020325795772190251487050535547981550465960228478297407995702324941118877701015321',
},
// vfmt on
]
fn test_big_mod_exponentiation_3() {
a := big.integer_from_string('3192874698137469817346981364918346578619384619387463987413') or {
panic('Could not read big integer')
fn test_big_mod_pow() {
for t in big_mod_pow_test_data {
a := big.integer_from_string(t.base) or { panic('Could not read decimal') }
x := big.integer_from_string(t.exponent) or { panic('Could not read decimal') }
m := big.integer_from_string(t.modulus) or { panic('Could not read decimal') }
r := big.integer_from_string(t.expected) or { panic('Could not read decimal') }
assert a.big_mod_pow(x, m) or { panic(err) } == r
}
b := big.integer_from_string('3104981983749813749137493871037') or {
panic('Could not read big integer')
}
c := big.integer_from_string('2137476918375698711341313') or {
panic('Could not read big integer')
}
result := big.integer_from_string('418107071760838517119254') or {
panic('Could not read big integer')
}
assert a.big_mod_pow(b, c) == result
}
fn test_gcd() {
@ -475,3 +511,22 @@ fn test_bit_len() ? {
assert true
}
}
struct ModInverseTest {
value string
modulus string
}
const mod_inverse_test_data = [
ModInverseTest{'1234567', '458948883992'},
ModInverseTest{'239487239847', '2410312426921032588552076022197566074856950548502459942654116941958108831682612228890093858261341614673227141477904012196503648957050582631942730706805009223062734745341073406696246014589361659774041027169249453200378729434170325843778659198143763193776859869524088940195577346119843545301547043747207749969763750084308926339295559968882457872412993810129130294592999947926365264059284647209730384947211681434464714438488520940127459844288859336526896320919633919'},
]
fn test_mod_inverse() ? {
for t in mod_inverse_test_data {
a := big.integer_from_string(t.value) or { panic('Could not read decimal') }
m := big.integer_from_string(t.modulus) or { panic('Could not read decimal') }
r := a.mod_inverse(m) or { panic('No multiplicative inverse in ring Z/mZ') }
assert (r * a) % m == big.one_int
}
}

View File

@ -0,0 +1,339 @@
module big
/*
for a detailed explanation on these internal functions and the algorithms they
are based on refer to https://github.com/vlang/v/pull/18461
*/
import math.bits
// internal struct to make passing montgomery values simpler
struct MontgomeryContext {
n Integer // |modulus|
ni Integer // n^(-1)
rr Integer // for conversions
}
// montgomery calculates a montgomery context for reductions to montgomery space based on
// the modulus provided in the integer `m`; assume m is odd and m != 0
fn (m Integer) montgomery() MontgomeryContext {
$if debug {
assert m != zero_int
assert m.is_odd()
}
n := m.abs()
b := u32(n.bit_len())
return MontgomeryContext{
n: n
// r = 2^(log_2(n))
// ri := multiplicative inverse of r in the ring Z/nZ
// ri * r == 1 (mod n)
// ni = ((ri * 2^(log_2(n))) - 1) / n
ni: (one_int.lshift(b).mod_inv(n).lshift(b) - one_int) / n
rr: one_int.lshift(b * 2) % n
}
}
// mont_odd calculates `a^x (mod m)`, where `m` is odd by reducing `a` to montgomery space
// and then exponentiating the value using the sliding window method and montgomery multiplication
// -----
// assumes a, x > 1 and m is odd
[direct_array_access]
fn (a Integer) mont_odd(x Integer, m Integer) Integer {
$if debug {
assert a > one_int && x > one_int
assert m.is_odd()
}
window := get_window_size(u32(x.bit_len()))
mut table := []Integer{len: 1 << window}
ctx := m.montgomery()
aa := if a.signum < 0 || a.abs_cmp(m) >= 0 {
a % m
} else {
a
}
table[0] = aa.to_mont(ctx)
{
d := table[0].mont_mul(table[0], ctx)
for i := 1; i < table.len; i++ {
table[i] = table[i - 1].mont_mul(d, ctx)
}
}
mut r := if m.digits.last() & (1 << (32 - 1)) != 0 {
mut rdigits := []u32{len: m.digits.len}
rdigits[0] = -m.digits[0]
for i := 1; i < m.digits.len; i++ {
rdigits[i] = ~m.digits[i]
}
Integer{
digits: rdigits
signum: 1
}
} else {
one_int.to_mont(ctx)
}
mut start := true
mut wstart := x.bit_len() - 1
mut wvalue := 0
mut wend := 0
for {
if !x.get_bit(u32(wstart)) {
if !start {
r = r.mont_mul(r, ctx)
}
if wstart == 0 {
break
}
wstart--
continue
}
wvalue = 1
wend = 0
for i := 1; i < window; i++ {
if wstart - i < 0 {
break
}
if x.get_bit(u32(wstart - i)) {
wvalue <<= (i - wend)
wvalue |= 1
wend = i
}
}
j := wend + 1
if !start {
for i := 0; i < j; i++ {
r = r.mont_mul(r, ctx)
}
}
r = r.mont_mul(table[wvalue >> 1], ctx)
wstart -= j
wvalue = 0
start = false
if wstart < 0 {
break
}
}
return r.from_mont(ctx)
}
// mont_even calculates `a^x (mod m)` where `m` is even. This is done by factoring the modulus
// `m` into an odd integer `m1` and an even multiple of 2, which we'll call m2.
// We then calculate:
// x1 = a^x (mod m1)
// x2 = a^x (mod m2)
//
// Exponentiation with the modulus `m1` can be done using the traditional montgomery method,
// whereas `m2` is done using binary exponentiation modulo `m2`, which is fast seeing as we
// simply mask the low bits.
//
// The result `y` then satisfies (where `==` denotes congruence):
// y == x1 (mod m1)
// y == x2 (mod m2)
//
// We then use the Chinese Remainder Theorem (mixed-radix conversion algorithm) to calculate `y`.
// y = x1 + m1 * t
// where
// t = (x2 - x1) * m1^(-1) (mod m2)
//
// The multiplicative inverse of m1 in Z/m2Z exists since it is odd, therefore we can safely
// use the unchecked internal function.
//
// See Montgomery Reduction with Even Modulus by Çetin Kaya Koç
// (https://cetinkayakoc.net/docs/j34.pdf)
// -----
// assumes a, x > 1 and m is even
[direct_array_access]
fn (a Integer) mont_even(x Integer, m Integer) Integer {
$if debug {
assert a > one_int && x > one_int
assert !m.is_odd()
}
// first, get the trailing zeros in m
mut j := u32(0)
for m.digits[j] == 0 {
j++
}
j = j * 32 + u32(bits.trailing_zeros_32(m.digits[j]))
m1, m2 := m.rshift(j), one_int.lshift(j)
$if debug {
assert m1 * m2 == m
assert m1.is_odd() && !m2.is_odd()
}
mut x1 := a.mont_odd(x, m1)
mut x2 := a.exp_binary(x, m2)
m2n := u32(m2.bit_len()) - 1
m1i := m1.mod_inv(m2)
$if debug {
assert (m1i * m1).mask_bits(m2n) == one_int
}
t1 := x1.mask_bits(m2n)
t2 := x2.mask_bits(m2n)
t := (if t2.abs_cmp(t1) >= 0 {
(t2 - t1).mask_bits(m2n)
} else {
// (x2 - x1) % m2 = 1 + ((~((x2 % m2) - (x1 % m2))) % m2)
(t1 - t2).abs().bitwise_not().mask_bits(m2n) + one_int
} * m1i).mask_bits(m2n)
return x1 + m1 * t
}
// exp_binary calculates `a^x (mod m)`, where m is a power of 2
// -----
// assumes a, x > 1 and m = 2^n
[direct_array_access]
fn (a Integer) exp_binary(x Integer, m Integer) Integer {
$if debug {
assert a > one_int && x > one_int
assert m.is_power_of_2()
}
n := u32(m.bit_len()) - 1
window := get_window_size(u32(x.bit_len()))
mut table := []Integer{len: 1 << window}
// table[i] = a^i + 1, since a^0 is known to be 1, there is no point
// in eventually multiplying by one, so the for loop part continues until it
// meets a block starting with a set bit
table[0] = a.mask_bits(n)
d := (table[0] * table[0]).mask_bits(n)
for i := 1; i < table.len; i++ {
table[i] = (table[i - 1] * d).mask_bits(n)
}
mut r := one_int
mut start := true
mut wstart := if x.bit_len() - 1 > n {
int(n)
} else {
x.bit_len() - 1
}
mut wend := 0
mut wvalue := 1
for wstart >= 0 {
if !x.get_bit(u32(wstart)) {
// no point squaring while r = 1
if !start {
r = (r * r).mask_bits(n)
}
if wstart == 0 {
break
}
wstart--
continue
}
// the bit x[wstart] is now known to be 1, so no reason to check it again
for i := 1; i < window; i++ {
if wstart - i < 0 {
break
}
if x.get_bit(u32(wstart - i)) {
wvalue <<= (i - wend) // i - wend is the amount of 0 bits that have been read
wvalue |= 1
wend = i
}
}
j := wend + 1
// same as before; r has not been populated yet, so squaring wouldn't do anything
if !start {
for i := 0; i < j; i++ {
r = (r * r).mask_bits(n)
}
}
r = (r * table[wvalue >> 1]).mask_bits(n)
wstart -= j
wvalue = 1
wend = 0
start = false
}
return r.mask_bits(n)
}
// generally sticking to a window size of 4 for sliding window exponentiation
// works well as the table stays relatively small and the blocks aren't too large.
// though in terms of larger exponents it's faster to use larger windows (going over
// a window size of 6, would cause extremely large table sizes, hindering performance)
//
// 6 is already a large window to use, requiring 64 elements in the table, so we'll
// limit it to only the largest of exponents
//
// according to the paper on montgomery multiplication by Shay Gueron, for the
// case of the exponent being 512 bits a window size of 5 is considered optimal
[inline]
fn get_window_size(n u32) int {
return if n > 768 {
6
} else if n > 256 {
5
} else if n > 32 {
4
} else {
3
}
}
// mont_mul performs multiplication of two variables in montgomery
// space and reduces the result to montgomery space
fn (a Integer) mont_mul(b Integer, ctx MontgomeryContext) Integer {
if (a.digits.len + b.digits.len) > 2 * ctx.n.digits.len {
return zero_int
}
t := a * b
return t.from_mont(ctx)
}
fn (a Integer) to_mont(ctx MontgomeryContext) Integer {
return a.mont_mul(ctx.rr, ctx)
}
// See Fig. 1. "A Montgomery Reduction lemma" in
// Efficient Software Implementations of Modular Exponentiation by Shay Gueron
// (https://eprint.iacr.org/2011/239.pdf)
fn (a Integer) from_mont(ctx MontgomeryContext) Integer {
log2n := u32(ctx.n.bit_len())
r := (a + ((a.mask_bits(log2n) * ctx.ni).mask_bits(log2n) * ctx.n)).rshift(log2n)
return if r.abs_cmp(ctx.n) >= 0 {
r - ctx.n
} else {
r
}
}

View File

@ -415,16 +415,55 @@ pub fn (a Integer) % (b Integer) Integer {
return r
}
// mask_bits is the equivalent of `a % 2^n` (only when `a >= 0`), however doing a full division
// run for this would be a lot of work when we can simply "cut off" all bits to the left of
// the `n`th bit.
[direct_array_access]
fn (a Integer) mask_bits(n u32) Integer {
$if debug {
assert a.signum >= 0
}
if a.digits.len == 0 || n == 0 {
return zero_int
}
w := n / 32
b := n % 32
if w >= a.digits.len {
return a
}
return Integer{
digits: if b == 0 {
mut storage := []u32{len: int(w)}
for i := 0; i < storage.len; i++ {
storage[i] = a.digits[i]
}
storage
} else {
mut storage := []u32{len: int(w) + 1}
for i := 0; i < storage.len; i++ {
storage[i] = a.digits[i]
}
storage[w] &= ~(u32(-1) << b)
storage
}
signum: 1
}
}
// pow returns the integer `a` raised to the power of the u32 `exponent`.
pub fn (a Integer) pow(exponent u32) Integer {
pub fn (base Integer) pow(exponent u32) Integer {
if exponent == 0 {
return one_int
}
if exponent == 1 {
return a.clone()
return base.clone()
}
mut n := exponent
mut x := a
mut x := base
mut y := one_int
for n > 1 {
if n & 1 == 1 {
@ -436,63 +475,74 @@ pub fn (a Integer) pow(exponent u32) Integer {
return x * y
}
// mod_pow returns the integer `a` raised to the power of the u32 `exponent` modulo the integer `divisor`.
pub fn (a Integer) mod_pow(exponent u32, divisor Integer) Integer {
// mod_pow returns the integer `a` raised to the power of the u32 `exponent` modulo the integer `modulus`.
pub fn (base Integer) mod_pow(exponent u32, modulus Integer) Integer {
if exponent == 0 {
return one_int
}
if exponent == 1 {
return a % divisor
return base % modulus
}
mut n := exponent
mut x := a % divisor
mut x := base % modulus
mut y := one_int
for n > 1 {
if n & 1 == 1 {
y *= x % divisor
y *= x % modulus
}
x *= x % divisor
x *= x % modulus
n >>= 1
}
return x * y % divisor
return x * y % modulus
}
// big_mod_power returns the integer `a` raised to the power of the integer `exponent` modulo the integer `divisor`.
// big_mod_pow returns the integer `base` raised to the power of the integer `exponent` modulo the integer `modulus`.
[direct_array_access]
pub fn (a Integer) big_mod_pow(exponent Integer, divisor Integer) Integer {
pub fn (base Integer) big_mod_pow(exponent Integer, modulus Integer) !Integer {
if exponent.signum < 0 {
panic('Exponent needs to be non-negative.')
return error('math.big: Exponent needs to be non-negative.')
}
if exponent.signum == 0 {
// this goes first as otherwise 1 could be returned incorrectly if base == 1
if modulus.bit_len() <= 1 {
return zero_int
}
// x^0 == 1 || 1^x == 1
if exponent.signum == 0 || base.bit_len() == 1 {
return one_int
}
mut x := a % divisor
mut y := one_int
mut n := u32(0)
// For all but the last digit of the exponent
for index in 0 .. exponent.digits.len - 1 {
n = exponent.digits[index]
for _ in 0 .. 32 {
if n & 1 == 1 {
y *= x % divisor
}
x *= x % divisor
n >>= 1
}
// 0^x == 0 (x != 0 due to previous clause)
if base.signum == 0 {
return one_int
}
// Last digit of the exponent
n = exponent.digits.last()
for n > 1 {
if n & 1 == 1 {
y *= x % divisor
if exponent.bit_len() == 1 {
// x^1 without mod == x
if modulus.signum == 0 {
return base
}
x *= x % divisor
n >>= 1
// x^1 (mod m) === x % m
return base % modulus
}
return x * y % divisor
// the amount of precomputation in windowed exponentiation (done in the montgomery and binary
// windowed exponentiation algorithms) is far too costly for small sized exponents, so
// we redirect the call to mod_pow
return if exponent.digits.len > 1 {
if modulus.is_odd() {
// modulus is odd, therefore we use the normal
// montgomery modular exponentiation algorithm
base.mont_odd(exponent, modulus)
} else if modulus.is_power_of_2() {
base.exp_binary(exponent, modulus)
} else {
base.mont_even(exponent, modulus)
}
} else {
base.mod_pow(exponent.digits[0], modulus)
}
}
// inc returns the integer `a` incremented by 1.
@ -956,6 +1006,98 @@ fn gcd_binary(x Integer, y Integer) Integer {
return b.lshift(shift)
}
// mod_inverse calculates the multiplicative inverse of the integer `a` in the ring `/n`.
// Therefore, the return value `x` satisfies `a * x == 1 (mod m)`.
// -----
// An error is returned if `a` and `n` are not relatively prime, i.e. `gcd(a, n) != 1` or
// if n <= 1
[inline]
pub fn (a Integer) mod_inverse(n Integer) !Integer {
return if n.bit_len() <= 1 {
error('math.big: Modulus `n` must be greater than 1')
} else if a.gcd(n) != one_int {
error('math.big: No multiplicative inverse')
} else {
a.mod_inv(n)
}
}
// this is an internal function, therefore we assume valid inputs,
// i.e. m > 1 and gcd(a, m) = 1
// see pub fn mod_inverse for details on the result
// -----
// the algorithm is based on the Extended Euclidean algorithm which computes `ax + by = d`
// in this case `b` is the input integer `a` and `a` is the input modulus `m`. The extended
// Euclidean algorithm calculates the greatest common divisor `d` and two coefficients `x` and `y`
// satisfying the above equality.
//
// For the sake of clarity, we refer to the input integer `a` as `b` and the integer `m` as `a`.
// If `gcd(a, b) = d = 1` then the coefficient `y` is known to be the multiplicative inverse of
// `b` in ring `Z/aZ`, since reducing `ax + by = 1` by `a` yields `by == 1 (mod a)`.
[direct_array_access]
fn (a Integer) mod_inv(m Integer) Integer {
mut n := Integer{
digits: m.digits.clone()
signum: 1
}
mut b := a
mut x := one_int
mut y := zero_int
if b.signum < 0 || b.abs_cmp(n) >= 0 {
b = b % n
}
mut sign := -1
for b != zero_int {
q, r := if n.bit_len() == b.bit_len() {
one_int, n - b
} else {
n.div_mod(b)
}
n = b
b = r
// tmp := q * x + y
tmp := if q == one_int {
x
} else if q.digits.len == 1 && q.digits[0] & (q.digits[0] - 1) == 0 {
x.lshift(u32(bits.trailing_zeros_32(q.digits[0])))
} else {
q * x
} + y
y = x
x = tmp
sign = -sign
}
if sign < 0 {
y = m - y
}
$if debug {
assert n == one_int
}
return if y.signum > 0 && y.abs_cmp(m) < 0 {
y
} else {
y % m
}
}
[direct_array_access; inline]
fn (x Integer) is_odd() bool {
return x.digits[0] & 1 == 1
}
// is_power_of_2 returns true when the integer `x` satisfies `2^n`, where `n >= 0`
[inline]
pub fn (x Integer) is_power_of_2() bool {
return x.bitwise_and(x - one_int).bit_len() == 0
}
// bit_len returns the number of bits required to represent the integer `a`.
[inline]
pub fn (x Integer) bit_len() int {