Advertisement
Guest User

ModPow in LSL

a guest
Nov 11th, 2024
33
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Linden Scripting 5.25 KB | Source Code | 0 0
  1. // modular reduction: compute ab mod p
  2. // assumes 0 ≤ a < p, 0 ≤ b < p, p > 2
  3. integer _reduce(integer a, integer b, integer p) {
  4.     /* calculate ab using long multiplication of 16bit limbs */
  5.  
  6.     // split a, b into 16bit limbs
  7.     integer al = a & 0xFFFF;
  8.     integer ah = (a>>16) & 0xFFFF;
  9.     integer bl = b & 0xFFFF;
  10.     integer bh = (b>>16) & 0xFFFF;
  11.  
  12.     // intermediate limb products
  13.     integer p0 = al * bl;
  14.     integer p1 = ah * bl;
  15.     integer p2 = al * bh;
  16.  
  17.     // calculate upper limb of the 64bit product's lower 32 bits.
  18.     // any overflow will be carry to add to the upper 32bits of he 64bit product
  19.     a = ((p0 >> 16) & 0xFFFF) + (p1 & 0xFFFF) + (p2 & 0xFFFF);
  20.  
  21.     // 64bit product ab, split across 2 32bit integers (store in ah, al)
  22.     al = (p0 & 0xFFFF) | (a << 16);
  23.     ah = (a >> 16) + ((p1 >> 16) & 0xFFFF) + ((p2 >> 16) & 0xFFFF) + ah * bh;
  24.  
  25.     // if we just have a 31 bit product, can just use builtin operator
  26.     if(!ah && (al > 0)) return al % p;
  27.  
  28.     /* now divide by p to calculate remainder */
  29.  
  30.     // determine number of bits set (store in a)
  31.     if(ah) {
  32.         // bitcount is 32 + number of bits in ah
  33.         a = 32;
  34.         b = ah;
  35.     } else if(al & 0x80000000) a = 32; // msb set, so bitcount is 32
  36.     else b = al; // bitcount is number of bits in al
  37.     if(b) do ++a; while(b = b >> 1);
  38.  
  39.     integer r; // remainder R to calculate
  40.  
  41.     // 64 bit mask M (store in p0,p1)
  42.     // Used to select the dividend bit to bring down
  43.     p0 = 0; p1 = 0;
  44.     if(a > 32)
  45.         p0 = 1 << (a - 33);
  46.     else
  47.         p1 = 1 << (a - 1);
  48.  
  49.     // long binary division, ignoring quotient
  50.     // starting with the MSB of the dividend, pull
  51.     // it down to build the remainder. Once the
  52.     // remainder exceeds the divisor, subtract the
  53.     // divisor to get the next remainder to continue
  54.     // building with pulled down dividend bits.
  55.     // Once all the dividend bits have ben pulled
  56.     // down you have the resulting remainder
  57.     for(; a; --a) {
  58.         // pull down the dividend bit and build the
  59.         // remainder
  60.         if(p0)
  61.             r = (r << 1) | ((ah & p0) != 0);
  62.         else
  63.             r = (r << 1) | ((al & p1) != 0);
  64.  
  65.         if((r >= p) || (r < 0))
  66.             // remainder exceeded divisor,
  67.             // so subtract divisor
  68.             r -= p;
  69.  
  70.         // next dividend bit selector (M = M >> 1)
  71.         if(p1) p1 = (p1 >> 1) & 0x7FFFFFFF;
  72.         else if(!(p0 = p0 >> 1)) p1 = 0x80000000;
  73.     }
  74.  
  75.     return r;
  76. }
  77.  
  78. // compute xⁿ mod p
  79. // uses exponentiation by squaring method and
  80. // utilises fact that xy mod n = (x mod n)(y mod n) mod n
  81. integer ModPow(integer x, integer n, integer p){
  82.     // don't support -ve powers
  83.     if(n < 0) return 0;
  84.     // modulo less than 2 makes no sense
  85.     if(p < 2) return 0;
  86.  
  87.     // if modulo fits within 16bits, we can trivially
  88.     // use * and % operators, no need to use the
  89.     // expensive _reduce UDF
  90.     integer t = p < 0x10000;
  91.  
  92.     integer r = 1; // result
  93.  
  94.     // trivial reduction
  95.     if(x >= p) x = x % p;
  96.  
  97.     if(n) do {
  98.         if(n&1)
  99.         if(r>1) {
  100.             // bit set, so current square mod p
  101.             //  is a factor of the remainder
  102.             if(t) r = (r * x) % p;
  103.             else r = _reduce(r, x, p);
  104.         } else r = x;
  105.  
  106.         // calculate next square mod p
  107.         if(n = n >> 1)
  108.         if(t) x = (x * x) % p;
  109.         else x = _reduce(x, x, p);
  110.     } while(n);
  111.  
  112.     return r;
  113. }
  114.  
  115. default
  116. {
  117.     state_entry()
  118.     {
  119.         integer x; integer n; integer p;
  120.         integer e; integer r;
  121.         list d = [
  122.             // X. N, P, Expected
  123.             // Expected taken from https://www.dcode.fr/modular-exponentiation
  124.             2386073, 2, 2147483647, 365213132,
  125.             54023227, 188543765, 128767565, 72911872,
  126.             105840436, 187237174, 131390926, 37550416,
  127.             41160897, 165236876, 146705624, 57948809,
  128.             61936308, 110630338 , 65008019, 11358659,
  129.             80557, 2111897, 7177, 2959
  130.             ];
  131.         integer l = llGetListLength(d) - 1;
  132.         float t;
  133.  
  134.         integer i = -1;
  135.         llResetTime();
  136.         do {
  137.             x = llList2Integer(d, ++i);
  138.             n = llList2Integer(d, ++i);
  139.             p = llList2Integer(d, ++i);
  140.             e = llList2Integer(d, ++i);
  141.             r = ModPow(x, n, p);
  142.             llOwnerSay((string)[
  143.                 "ModPow(x=", x, "; n=", n, "; p=", p,
  144.                 ")\n=> expected=", e, "; actual=", r, " ",
  145.                 llGetSubString("✘✔", r==e, r==e)
  146.                 ]);
  147.         } while (i < l);
  148.         t = llGetTime();
  149.         llOwnerSay((string)[ "time taken: ", t, " seconds" ]);
  150.  
  151.         i = -1;
  152.         llResetTime();
  153.         do {
  154.             x = llList2Integer(d, ++i);
  155.             n = llList2Integer(d, ++i);
  156.             p = llList2Integer(d, ++i);
  157.             e = llList2Integer(d, ++i);
  158.             r = llModPow(x, n, p);
  159.             llOwnerSay((string)[
  160.                 "llModPow(x=", x, "; n=", n, "; p=", p,
  161.                 ")\n=> expected=", e, "; actual=", r, " ",
  162.                 llGetSubString("✘✔", r==e, r==e)
  163.                 ]);
  164.         } while (i < l);
  165.         t = llGetTime();
  166.         llOwnerSay((string)[ "time taken: ", t, " seconds" ]);
  167.     }
  168. }
  169.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement