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  }