github.com/aergoio/aergo@v1.3.1/contract/lgmp.c (about) 1 #include <stdlib.h> 2 #include <string.h> 3 #include <stdint.h> 4 5 #include "lua.h" 6 #include "lauxlib.h" 7 #include "lgmp.h" 8 #include "math.h" 9 10 #define lua_boxpointer(L,u) \ 11 (*(void **)(lua_newuserdata(L, sizeof(void *))) = (u)) 12 #define MPZ(a) ((mpz_ptr)(a->mpptr)) 13 14 static const char *mp_num_memory_error="bignum not enough memory"; 15 static const char *mp_num_invalid_number="bignum invalid number string"; 16 static const char *mp_num_divide_zero="bignum divide by zero"; 17 static const char *mp_num_limited_max="bignum over max limit"; 18 static const char *mp_num_limited_min="bignum under min limit"; 19 static const char *mp_num_is_negative ="bignum not allowed negative value"; 20 static const char *mp_max_bignum = "115792089237316195423570985008687907853269984665640564039457584007913129639935"; 21 static const char *mp_min_bignum = "-115792089237316195423570985008687907853269984665640564039457584007913129639935"; 22 23 mp_num _max_; 24 mp_num _min_; 25 26 static mp_num bn_alloc (int type) { 27 mp_num new = malloc(sizeof(bn_struct)); 28 if (new == NULL) 29 return NULL; 30 new->type = type; 31 mpz_ptr pz = malloc(sizeof(mpz_t)); 32 if (pz == NULL) 33 return NULL; 34 mpz_init(pz); 35 new->mpptr = pz; 36 return new; 37 } 38 39 static void mp_num_free(mp_num x) { 40 mpz_clear(x->mpptr); 41 free(x->mpptr); 42 free(x); 43 } 44 45 static void Bnew(lua_State *L, mp_num x) 46 { 47 if (mpz_cmp(x->mpptr, _max_->mpptr) > 0) { 48 mp_num_free(x); 49 luaL_error(L, mp_num_limited_max); 50 } else if (mpz_cmp(x->mpptr, _min_->mpptr) < 0) { 51 mp_num_free(x); 52 luaL_error(L, mp_num_limited_min); 53 } 54 lua_boxpointer(L,x); 55 luaL_getmetatable(L,MYTYPE); 56 lua_setmetatable(L,-2); 57 } 58 59 60 const char *lua_set_bignum(lua_State *L, char *s) 61 { 62 mp_num x; 63 x = bn_alloc(BN_Integer); 64 if (x == NULL) { 65 return mp_num_memory_error; 66 } 67 if (mpz_init_set_str(x->mpptr, s, 0) != 0) { 68 mp_num_free(x); 69 return mp_num_invalid_number; 70 } 71 Bnew(L, x); 72 return NULL; 73 } 74 75 mp_num Bgetbnum(lua_State *L, int i) 76 { 77 return (mp_num)*((void**)luaL_checkudata(L,i,MYTYPE)); 78 } 79 80 int lua_isbignumber(lua_State *L, int i) 81 { 82 if (luaL_testudata(L, i, MYTYPE) != NULL) 83 return 1; 84 return 0; 85 } 86 87 int Bis(lua_State *L) 88 { 89 lua_pushboolean(L, lua_isbignumber(L, 1) != 0); 90 return 1; 91 } 92 93 static mp_num Bget(lua_State *L, int i) 94 { 95 switch (lua_type(L, i)) 96 { 97 case LUA_TNUMBER: 98 { 99 mp_num x; 100 double d = lua_tonumber(L, i); 101 x = bn_alloc(BN_Integer); 102 if (x == NULL) 103 luaL_error(L, mp_num_memory_error); 104 if (isnan(d) || isinf(d)) { 105 luaL_error(L, "can't convert nan or infinity"); 106 } 107 mpz_init_set_d(x->mpptr, d); 108 Bnew(L, x); 109 lua_replace(L, i); 110 return x; 111 112 } 113 case LUA_TSTRING: 114 { 115 mp_num x; 116 const char *s = lua_tostring(L, i); 117 x = bn_alloc(BN_Integer); 118 if (x == NULL) 119 luaL_error(L, mp_num_memory_error); 120 if (mpz_init_set_str(x->mpptr, s, 0) != 0) { 121 mp_num_free(x); 122 luaL_error(L, mp_num_invalid_number); 123 } 124 Bnew(L, x); 125 lua_replace(L, i); 126 return x; 127 } 128 default: 129 return *((void**)luaL_checkudata(L,i,MYTYPE)); 130 } 131 return NULL; 132 } 133 134 static mp_num bn_copy (mp_num src) 135 { 136 mp_num new = bn_alloc(src->type); 137 mpz_set(new->mpptr, src->mpptr); 138 139 return new; 140 } 141 142 static int Bdo1(lua_State *L, void (*f)(mpz_ptr a, mpz_srcptr b, mpz_srcptr c), char is_div) 143 { 144 mp_num a = Bget(L, 1); 145 mp_num b = Bget(L, 2); 146 mp_num c; 147 148 if (is_div == 1 && mpz_sgn(MPZ(b)) == 0) 149 luaL_error(L, mp_num_divide_zero); 150 151 c = bn_alloc(a->type); 152 if (c == NULL) 153 luaL_error(L, mp_num_memory_error); 154 f(MPZ(c), MPZ(a), MPZ(b)); 155 Bnew(L, c); 156 return 1; 157 } 158 159 char *lua_get_bignum_str(lua_State *L, int idx) 160 { 161 char *res; 162 mp_num a = Bget(L, idx); 163 char *str = malloc(mpz_sizeinbase (a->mpptr, MPZ_BASE) + 2); 164 if (str == NULL) 165 return NULL; 166 167 res = mpz_get_str(str, MPZ_BASE, a->mpptr); 168 return res; 169 } 170 171 long int lua_get_bignum_si(lua_State *L, int idx) 172 { 173 mp_num a = Bget(L, idx); 174 if (mpz_fits_slong_p(MPZ(a)) == 0) 175 return 0; 176 return mpz_get_si(MPZ(a)); 177 } 178 179 int lua_bignum_is_zero(lua_State *L, int idx) 180 { 181 mp_num a = Bget(L, idx); 182 return mpz_sgn(MPZ(a)); 183 } 184 185 static int Btostring(lua_State *L) 186 { 187 char *res = lua_get_bignum_str(L, 1); 188 if (res == NULL) 189 luaL_error(L, mp_num_memory_error); 190 lua_pushstring(L, res); 191 free(res); 192 return 1; 193 } 194 195 static int Btonumber(lua_State *L) 196 { 197 mp_num a = Bget(L, 1); 198 lua_pushnumber(L, mpz_get_d(a->mpptr)); 199 return 1; 200 } 201 202 static int Btobyte(lua_State *L) 203 { 204 char *bn; 205 size_t size; 206 207 mp_num a = Bget(L, 1); 208 if (mpz_sgn(MPZ(a)) < 0) 209 luaL_error(L, mp_num_is_negative); 210 211 bn = mpz_export(NULL, &size, 1, 1, 1, 0, a->mpptr); 212 if (bn == NULL) { 213 bn = calloc(sizeof(char),1); 214 size = 1; 215 } 216 217 lua_pushlstring(L, bn, size); 218 free (bn); 219 return 1; 220 } 221 222 static int Bfrombyte(lua_State *L) 223 { 224 const char *bn; 225 size_t size; 226 mp_num x; 227 x = bn_alloc(BN_Integer); 228 229 bn = luaL_checklstring(L, 1, &size); 230 231 mpz_import(MPZ(x), size, 1, 1, 1, 0, bn); 232 233 Bnew(L, x); 234 return 1; 235 } 236 237 static int Biszero(lua_State *L) 238 { 239 mp_num a = Bget(L, 1); 240 lua_pushboolean(L, mpz_sgn(MPZ(a)) == 0); 241 242 return 1; 243 } 244 245 static int Bisneg(lua_State *L) 246 { 247 mp_num a = Bget(L, 1); 248 lua_pushboolean(L, (mpz_sgn(MPZ(a)) < 0)); 249 250 return 1; 251 } 252 253 static int Bnumber(lua_State *L) 254 { 255 Bget(L, 1); 256 lua_settop(L, 1); 257 return 1; 258 } 259 260 static int Bcompare(lua_State *L) 261 { 262 mp_num a = Bget(L, 1); 263 mp_num b = Bget(L, 2); 264 lua_pushinteger(L, mpz_cmp(a->mpptr, b->mpptr)); 265 return 1; 266 } 267 268 static int Beq(lua_State *L) 269 { 270 mp_num a = Bget(L, 1); 271 mp_num b = Bget(L, 2); 272 lua_pushboolean(L, mpz_cmp(a->mpptr, b->mpptr) == 0); 273 return 1; 274 } 275 276 static int Blt(lua_State *L) 277 { 278 mp_num a = Bget(L, 1); 279 mp_num b = Bget(L, 2); 280 lua_pushboolean(L, mpz_cmp(a->mpptr, b->mpptr) < 0); 281 return 1; 282 } 283 284 static int Badd(lua_State *L) /** add(x,y) */ 285 { 286 return Bdo1(L, mpz_add, 0); 287 } 288 289 static int Bsub(lua_State *L) /** sub(x,y) */ 290 { 291 return Bdo1(L, mpz_sub, 0); 292 } 293 294 static int Bmul(lua_State *L) /** mul(x,y) */ 295 { 296 return Bdo1(L, mpz_mul, 0); 297 } 298 299 static int Bpow(lua_State *L) /** pow(x,y) */ 300 { 301 mp_num a = Bget(L, 1); 302 mp_num b = Bget(L, 2); 303 mp_num c; 304 uint32_t remainder; 305 306 if (mpz_sgn(MPZ(b)) < 0) 307 luaL_error(L, mp_num_is_negative); 308 309 c = bn_alloc(a->type); 310 if (c == NULL) 311 luaL_error(L, mp_num_memory_error); 312 313 mpz_set_si(MPZ(c), 1); 314 315 if (mpz_sgn(MPZ(a)) == 0) { 316 Bnew(L, c); 317 return 1; 318 } 319 if (mpz_fits_sint_p(MPZ(a)) != 0) { 320 if (mpz_get_si(MPZ(a)) == 1) { 321 Bnew(L, c); 322 return 1; 323 } else if (mpz_get_si(MPZ(a)) == -1) { 324 if (mpz_odd_p(MPZ(b)) != 0) { 325 mpz_set_si(MPZ(c), -1); 326 } 327 Bnew(L, c); 328 return 1; 329 } 330 } 331 a = bn_copy(a); 332 b = bn_copy(b); 333 while (1) { 334 remainder = mpz_tdiv_q_ui(b->mpptr, b->mpptr, 2); 335 if (remainder == 1) { 336 mpz_mul(c->mpptr, c->mpptr, a->mpptr); 337 if (mpz_cmp(c->mpptr, _max_->mpptr) > 0 || mpz_cmp(a->mpptr, _min_->mpptr) < 0) { 338 mp_num_free(a); 339 mp_num_free(b); 340 mp_num_free(c); 341 luaL_error(L, mp_num_limited_max); 342 } 343 } 344 if (mpz_sgn(MPZ(b)) == 0) 345 break; 346 347 mpz_mul(a->mpptr, a->mpptr, a->mpptr); 348 if (mpz_cmp(a->mpptr, _max_->mpptr) > 0 || mpz_cmp(a->mpptr, _min_->mpptr) < 0) { 349 mp_num_free(a); 350 mp_num_free(b); 351 mp_num_free(c); 352 luaL_error(L, mp_num_limited_max); 353 } 354 } 355 Bnew(L, c); 356 mp_num_free(a); 357 mp_num_free(b); 358 return 1; 359 } 360 361 static int Bdiv(lua_State *L) /** div(x,y) */ 362 { 363 return Bdo1(L, mpz_tdiv_q, 1); 364 } 365 366 static int Bmod(lua_State *L) /** mod(x,y) */ 367 { 368 return Bdo1(L, mpz_tdiv_r, 1); 369 } 370 371 static int Bdivmod(lua_State *L) /** divmod(x,y) */ 372 { 373 mp_num a=Bget(L,1); 374 mp_num b=Bget(L,2); 375 mp_num q; 376 mp_num r; 377 378 if (mpz_sgn(MPZ(b)) == 0) 379 luaL_error(L, mp_num_divide_zero); 380 381 q = bn_alloc(a->type); 382 r = bn_alloc(a->type); 383 if (q == NULL || r == NULL) 384 luaL_error(L, mp_num_memory_error); 385 386 mpz_tdiv_qr(q->mpptr, r->mpptr, a->mpptr, b->mpptr); 387 Bnew(L, q); 388 Bnew(L, r); 389 return 2; 390 } 391 392 static int Bgc(lua_State *L) 393 { 394 mp_num x=Bget(L,1); 395 if (x != _min_ && x != _max_) 396 mp_num_free(x); 397 lua_pushnil(L); 398 lua_setmetatable(L,1); 399 return 0; 400 } 401 402 static int Bneg(lua_State *L) /** neg(x) */ 403 { 404 mp_num a=Bget(L,1); 405 mp_num res; 406 407 res = bn_alloc(a->type); 408 if (res == NULL) 409 luaL_error(L, mp_num_memory_error); 410 411 mpz_neg (res->mpptr, a->mpptr); 412 Bnew(L, res); 413 return 1; 414 } 415 416 static int Bpowmod(lua_State *L) /** powmod(x,y,m) */ 417 { 418 mp_num a=Bget(L,1); 419 mp_num k=Bget(L,2); 420 mp_num m=Bget(L,3); 421 mp_num r; 422 423 if (mpz_sgn(MPZ(k)) < 0) 424 luaL_error(L, mp_num_is_negative); 425 426 if (mpz_sgn(MPZ(m)) == 0) 427 luaL_error(L, mp_num_divide_zero); 428 429 r = bn_alloc(a->type); 430 if (r == NULL) 431 luaL_error(L, mp_num_memory_error); 432 433 mpz_powm(r->mpptr, a->mpptr, k->mpptr, m->mpptr); 434 Bnew(L, r); 435 return 1; 436 } 437 438 static int Bsqrt(lua_State *L) /** sqrt(x) */ 439 { 440 mp_num a=Bget(L,1); 441 mp_num res; 442 443 if (mpz_sgn(MPZ(a)) < 0) 444 luaL_error(L, mp_num_is_negative); 445 res = bn_alloc(a->type); 446 if (res == NULL) 447 luaL_error(L, mp_num_memory_error); 448 449 mpz_sqrt (res->mpptr, a->mpptr); 450 Bnew(L, res); 451 return 1; 452 } 453 454 const char *init_bignum() 455 { 456 _max_ = bn_alloc(BN_Integer); 457 if (_max_ == NULL) { 458 return mp_num_memory_error; 459 } 460 if (mpz_init_set_str(_max_->mpptr, mp_max_bignum, 0) != 0) { 461 mp_num_free(_max_); 462 return mp_num_invalid_number; 463 } 464 _min_ = bn_alloc(BN_Integer); 465 if (_min_ == NULL) { 466 return mp_num_memory_error; 467 } 468 if (mpz_init_set_str(_min_->mpptr, mp_min_bignum, 0) != 0) { 469 mp_num_free(_min_); 470 return mp_num_invalid_number; 471 } 472 return NULL; 473 } 474 475 static const luaL_Reg R[] = 476 { 477 { "__add", Badd }, /** __add(x,y) */ 478 { "__div", Bdiv }, /** __div(x,y) */ 479 { "__eq", Beq }, /** __eq(x,y) */ 480 { "__gc", Bgc }, 481 { "__lt", Blt }, /** __lt(x,y) */ 482 { "__mod", Bmod }, /** __mod(x,y) */ 483 { "__mul", Bmul }, /** __mul(x,y) */ 484 { "__pow", Bpow }, /** __pow(x,y) */ 485 { "__sub", Bsub }, /** __sub(x,y) */ 486 { "__tostring", Btostring}, /** __tostring(x) */ 487 { "__unm", Bneg }, /** __unm(x) */ 488 { "add", Badd }, 489 { "compare", Bcompare}, 490 { "div", Bdiv }, 491 { "divmod", Bdivmod }, 492 { "isneg", Bisneg }, 493 { "iszero", Biszero }, 494 { "mod", Bmod }, 495 { "mul", Bmul }, 496 { "neg", Bneg }, 497 { "number", Bnumber }, 498 { "pow", Bpow }, 499 { "powmod", Bpowmod }, 500 { "sqrt", Bsqrt }, 501 { "sub", Bsub }, 502 { "tonumber", Btonumber}, 503 { "tostring", Btostring}, 504 { "isbignum", Bis }, 505 { "tobyte", Btobyte }, 506 { "frombyte", Bfrombyte }, 507 { NULL, NULL } 508 }; 509 510 LUALIB_API int luaopen_gmp(lua_State *L) 511 { 512 luaL_newmetatable(L,MYTYPE); 513 lua_setglobal(L,MYNAME); 514 luaL_register(L,MYNAME,R); 515 lua_pushliteral(L,"version"); /** version */ 516 lua_pushliteral(L,MYVERSION); 517 lua_settable(L,-3); 518 lua_pushliteral(L,"__index"); 519 lua_pushvalue(L,-2); 520 lua_settable(L,-3); 521 522 return 1; 523 }