Repository: justmoon/node-bignum Branch: main Commit: ef2e02533e59 Files: 19 Total size: 79.4 KB Directory structure: gitextract_0bfbdiwo/ ├── .dntrc ├── .github/ │ └── workflows/ │ └── main.yml ├── .gitignore ├── .npmignore ├── README.markdown ├── appveyor.yml ├── bignum.cc ├── binding.gyp ├── examples/ │ ├── gen.js │ ├── perfect.js │ └── simple.js ├── index.js ├── package.json └── test/ ├── big.js ├── buf.js ├── gh52.js ├── isbignum.js ├── seed.js └── wincrash.js ================================================ FILE CONTENTS ================================================ ================================================ FILE: .dntrc ================================================ ## DNT config file ## see https://github.com/rvagg/dnt NODE_VERSIONS="\ v0.10.40 \ v0.12.7 \ " IOJS_VERSIONS="\ v1.8.4 \ v2.0.1 \ v2.5.0 \ v3.0.0 \ " OUTPUT_PREFIX="bignum-" TEST_CMD="\ cd /dnt/ && \ npm install node-gyp && \ npm install --nodedir=/usr/src/node && \ npm test; \ " LOG_OK_CMD="sed 's/^ ..32m100...0m .. tests$/ok/' | tail -2 | head -1" ================================================ FILE: .github/workflows/main.yml ================================================ name: CI on: [push, pull_request] jobs: build: runs-on: ${{ matrix.os }} strategy: matrix: os: [macos-latest, ubuntu-latest] # windows-latest needs openssl installed in C:\OpenSSL-Win64\ node-version: [10.x, 12.x, 13.x] steps: - name: Checkout uses: actions/checkout@v1 with: fetch-depth: 1 - name: Install and test with Node.js ${{ matrix.node-version }} uses: actions/setup-node@v1 with: node-version: ${{ matrix.node-version }} - run: npm install - run: npm run build --if-present - run: npm test env: CI: true ================================================ FILE: .gitignore ================================================ # Files .lock-wscript package-lock.json # Filetypes .*.swp # Paths /build /node_modules /coverage /binding /.nyc_output /docker ================================================ FILE: .npmignore ================================================ .lock-wscript .travis.yml appveyor.yml .dntrc .*.swp pre-gyp-publish.sh build node_modules coverage binding .nyc_output test examples docker ================================================ FILE: README.markdown ================================================ bignum ====== [![Build Status](https://github.com/justmoon/node-bignum/workflows/CI/badge.svg)](https://github.com/justmoon/node-bignum/actions?workflow=CI) Arbitrary precision integral arithmetic for Node.js using OpenSSL. This library is based on [node-bigint](https://github.com/substack/node-bigint) by [substack](https://github.com/substack), but instead of using libgmp, it uses the builtin bignum functionality provided by OpenSSL. The advantage is that OpenSSL is already part of Node.js, so this library does not add any external dependency whatsoever. BigInt ====== JavaScript now has a BigInt object. If you are using Node 10.4 or newer, you should use or migrate to [BigInt](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt). differences =========== When switching from node-bigint to node-bignum, please be aware of these differences: - Bignum rounds towards zero for integer divisions, e.g. `10 / -3 = -3`, whereas bigint rounds towards negative infinity, e.g. `10 / -3 = -4`. - nextPrime() is not supported. - sqrt() and root() are not supported. (Patches for the missing functionality are welcome.) example ======= simple.js --------- ```js var bignum = require('bignum'); var b = bignum('782910138827292261791972728324982') .sub('182373273283402171237474774728373') .div(8) ; console.log(b); ``` *** $ node simple.js perfect.js ---------- Generate the perfect numbers: ```js // If 2**n-1 is prime, then (2**n-1) * 2**(n-1) is perfect. var bignum = require('bignum'); for (var n = 0; n < 100; n++) { var p = bignum.pow(2, n).sub(1); if (p.probPrime(50)) { var perfect = p.mul(bignum.pow(2, n - 1)); console.log(perfect.toString()); } } ``` *** 6 28 496 8128 33550336 8589869056 137438691328 2305843008139952128 2658455991569831744654692615953842176 191561942608236107294793378084303638130997321548169216 methods[0] ========== bignum(n, base=10) ------------------ Create a new `bignum` from `n` and a base. `n` can be a string, integer, or another `bignum`. If you pass in a string you can set the base that string is encoded in. .toString(base=10) ------------------ Print out the `bignum` instance in the requested base as a string. bignum.fromBuffer(buf, opts) ---------------------------- Create a new `bignum` from a `Buffer`. The default options are: ```js { endian : 'big', size : 1, // number of bytes in each word } ``` Note that endian doesn't matter when size = 1. If you wish to reverse the entire buffer byte by byte, pass size: 'auto'. bignum.prime(bits, safe=true) ----------------------------- Generate a probable prime of length `bits`. If `safe` is true, it will be a "safe" prime of the form p=2p'+1 where p' is also prime. bignum.isBigNum(num) ----------------------------- Return true if `num` is identified as a bignum instance. Otherwise, return false. methods[1] ========== For all of the instance methods below you can write either ```js bignum.method(x, y, z) ``` or if x is a `bignum` instance`` ```js x.method(y, z) ``` .toNumber() ----------- Turn a `bignum` into a `Number`. If the `bignum` is too big you'll lose precision or you'll get ±`Infinity`. .toBuffer(opts) ------------- Return a new `Buffer` with the data from the `bignum`. The default options are: ```js { endian : 'big', size : 1, // number of bytes in each word } ``` Note that endian doesn't matter when size = 1. If you wish to reverse the entire buffer byte by byte, pass size: 'auto'. .add(n) ------- Return a new `bignum` containing the instance value plus `n`. .sub(n) ------- Return a new `bignum` containing the instance value minus `n`. .mul(n) ------- Return a new `bignum` containing the instance value multiplied by `n`. .div(n) ------- Return a new `bignum` containing the instance value integrally divided by `n`. .abs() ------ Return a new `bignum` with the absolute value of the instance. .neg() ------ Return a new `bignum` with the negative of the instance value. .cmp(n) ------- Compare the instance value to `n`. Return a positive integer if `> n`, a negative integer if `< n`, and 0 if `== n`. .gt(n) ------ Return a boolean: whether the instance value is greater than n (`> n`). .ge(n) ------ Return a boolean: whether the instance value is greater than or equal to n (`>= n`). .eq(n) ------ Return a boolean: whether the instance value is equal to n (`== n`). .lt(n) ------ Return a boolean: whether the instance value is less than n (`< n`). .le(n) ------ Return a boolean: whether the instance value is less than or equal to n (`<= n`). .and(n) ------- Return a new `bignum` with the instance value bitwise AND (&)-ed with `n`. .or(n) ------ Return a new `bignum` with the instance value bitwise inclusive-OR (|)-ed with `n`. .xor(n) ------- Return a new `bignum` with the instance value bitwise exclusive-OR (^)-ed with `n`. .mod(n) ------- Return a new `bignum` with the instance value modulo `n`. `m`. .pow(n) ------- Return a new `bignum` with the instance value raised to the `n`th power. .powm(n, m) ----------- Return a new `bignum` with the instance value raised to the `n`th power modulo `m`. .invertm(m) ----------- Compute the multiplicative inverse modulo `m`. .rand() ------- .rand(upperBound) ----------------- If `upperBound` is supplied, return a random `bignum` between the instance value and `upperBound - 1`, inclusive. Otherwise, return a random `bignum` between 0 and the instance value - 1, inclusive. .probPrime() ------------ Return whether the bignum is: * certainly prime (true) * probably prime ('maybe') * certainly composite (false) using [BN_is_prime_ex](http://www.openssl.org/docs/crypto/BN_generate_prime.html). .sqrt() ------- Return a new `bignum` that is the square root. This truncates. .root(n) ------- Return a new `bignum` that is the `nth` root. This truncates. .shiftLeft(n) ------------- Return a new `bignum` that is the `2^n` multiple. Equivalent of the `<<` operator. .shiftRight(n) -------------- Return a new `bignum` of the value integer divided by `2^n`. Equivalent of the `>>` operator. .gcd(n) ------- Return the greatest common divisor of the current `bignum` with `n` as a new `bignum`. .jacobi(n) ------- Return the Jacobi symbol (or Legendre symbol if `n` is prime) of the current `bignum` (= a) over `n`. Note that `n` must be odd and >= 3. 0 <= a < n. Returns -1 or 1 as an int (NOT a bignum). Throws an error on failure. .bitLength() ------------ Return the number of bits used to represent the current `bignum`. install ======= To compile the package, your system needs to be set up for building Node.js modules. You can install node-bignum with [npm](http://npmjs.org): npm install bignum develop ======= You can clone the git repo and compile with git clone git://github.com/justmoon/node-bignum.git cd node-bignum npm install Run the tests with npm test ================================================ FILE: appveyor.yml ================================================ environment: node_pre_gyp_accessKeyId: secure: EXM80HyHBdjKthrNyOlVa/8KKy7m5TdzTtGw0JmnaTs= node_pre_gyp_secretAccessKey: secure: PiO+DWUG15lw8VbOG2LRQHDUu2dn5w/fnY1MNXK5IgO35K37q4k7Y2YDPKqvjHgH # kudos to serialport for much of this matrix: - nodejs_version: "4" - nodejs_version: "6" - nodejs_version: "8" - nodejs_version: "10" platform: - x86 - x64 install: - ps: Update-NodeJsInstallation (Get-NodeJsLatestBuild $env:nodejs_version) $env:platform; - ps: $env:Path += ";$(pwd)\node_modules\.bin"; - ps: > @{ "nodejs_version" = $env:nodejs_version "platform" = $env:platform "node binary version" = $(node -v) "node platform@arch" = $(node -p 'process.platform + process.arch') "npm version" = $(npm -v) "APPVEYOR_REPO_COMMIT_MESSAGE" = $env:APPVEYOR_REPO_COMMIT_MESSAGE "git latest tag" = "$(git describe --tags --always HEAD)" "appveyor_repo_tag" = $env:appveyor_repo_tag } | Out-String | Write-Host; # work around bug in npm 2.15.1 where checksums were coming back bad (node 0.12) - ps: > if ($(npm -v) -eq "2.15.1") { npm install -g npm@3 | Write-Host; } npm -v | Write-Host; # work around an issue with node-gyp v3.3.1 and node 4x # package.json has no certificates in it so we're cool # https://github.com/nodejs/node-gyp/issues/921 - ps: npm config set -g cafile=package.json | Write-Host; - ps: npm config set -g strict-ssl=false | Write-Host; build_script: - IF /I "%platform%"=="x86" (SET target_arch="ia32") ELSE (SET target_arch="x64") - IF /I "%platform%"=="x64" ECHO x64 && CALL "C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat" amd64 - IF /I "%platform%"=="x86" ECHO x86 && CALL "C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat" x86 - npm install --build-from-source --msvs_version=2013 test_script: - npm test - node-pre-gyp package 2>&1 - node-pre-gyp unpublish publish --release 2>&1 - node-pre-gyp clean - npm install --fallback-to-build=false deploy: off version: "{build}" ================================================ FILE: bignum.cc ================================================ #include #include #include #include #include #include #include #include #include #include using namespace v8; using namespace node; using namespace std; #define REQ_STR_ARG(I, VAR) \ if (info.Length()<= (I) || !info[I]->IsString()) { \ Nan::ThrowTypeError("Argument " #I " must be a string"); \ return; \ } \ Local VAR = Local::Cast(info[I]); #define REQ_UTF8_ARG(I, VAR) \ if (info.Length() <= (I) || !info[I]->IsString()) { \ Nan::ThrowTypeError( \ "Argument " #I " must be a utf8 string"); \ return; \ } \ String::Utf8Value VAR(info[I]->ToString()); #define REQ_INT32_ARG(I, VAR) \ if (info.Length() <= (I) || !info[I]->IsInt32()) { \ Nan::ThrowTypeError("Argument " #I " must be an int32"); \ return; \ } \ int32_t VAR = info[I]->ToInt32()->Value(); #define REQ_UINT32_ARG(I, VAR) \ if (info.Length() <= (I) || !info[I]->IsUint32()) { \ Nan::ThrowTypeError("Argument " #I " must be a uint32"); \ return; \ } \ uint32_t VAR = Nan::To(info[I]).FromJust(); #define REQ_INT64_ARG(I, VAR) \ if (info.Length() <= (I) || !info[I]->IsNumber()) { \ Nan::ThrowTypeError("Argument " #I " must be an int64"); \ return; \ } \ int64_t VAR = info[I]->ToInteger(info.GetIsolate()->GetCurrentContext()).ToLocalChecked()->Value(); #define REQ_UINT64_ARG(I, VAR) \ if (info.Length() <= (I) || !info[I]->IsNumber()) { \ Nan::ThrowTypeError("Argument " #I " must be a uint64"); \ return; \ } \ uint64_t VAR = Nan::To(info[I]).ToLocalChecked()->Value(); #define REQ_BOOL_ARG(I, VAR) \ if (info.Length() <= (I) || !info[I]->IsBoolean()) { \ Nan::ThrowTypeError("Argument " #I " must be a boolean"); \ return; \ } \ bool VAR = Nan::To(info[I]).ToLocalChecked()->Value(); #define WRAP_RESULT(RES, VAR) \ Local arg[1] = { Nan::New(static_cast(RES)) }; \ Local VAR = Nan::NewInstance( \ Nan::New(constructor_template)->GetFunction(info.GetIsolate()->GetCurrentContext()).ToLocalChecked(), \ 1, \ arg \ ).ToLocalChecked(); class AutoBN_CTX { protected: BN_CTX* ctx; BN_CTX* operator=(BN_CTX* ctx_new) { return ctx = ctx_new; } public: AutoBN_CTX() { ctx = BN_CTX_new(); // TODO: Handle ctx == NULL } ~AutoBN_CTX() { if (ctx != NULL) BN_CTX_free(ctx); } operator BN_CTX*() { return ctx; } BN_CTX& operator*() { return *ctx; } BN_CTX** operator&() { return &ctx; } bool operator!() { return (ctx == NULL); } }; /** * BN_jacobi_priv() computes the Jacobi symbol of A with respect to N. * * Hence, *jacobi = 1 when the jacobi symbol is unity and *jacobi = -1 when the * jacobi symbol is -1. N must be odd and >= 3. It is required that 0 <= A < N. * * When successful 0 is returned. -1 is returned on failure. * * This is an implementation of an iterative version of Algorithm 2.149 on page * 73 of the book "Handbook of Applied Cryptography" by Menezes, Oorshot, * Vanstone. Note that there is a typo in step 1. Step 1 should return the value * 1. The algorithm has a running time of O((lg N)^2) bit operations. * * @author Adam L. Young */ int BN_jacobi_priv(const BIGNUM *A,const BIGNUM *N,int *jacobi, BN_CTX *ctx) { int e,returnvalue=0,s,bit0,bit1,bit2,a1bit0,a1bit1; BIGNUM *zero,*a1,*n1,*three,*tmp; if (!jacobi) return -1; *jacobi = 1; if ((!A) || (!N) || (!ctx)) return -1; if (!BN_is_odd(N)) return -1; /* ERROR: BN_jacobi() given an even N */ if (BN_cmp(A,N) >= 0) return -1; n1=BN_new();zero=BN_new();a1=BN_new();three=BN_new();tmp=BN_new(); BN_set_word(zero,0); BN_set_word(three,3); if (BN_cmp(N,three) < 0) { /* This function was written by Adam L. Young */ returnvalue = -1; goto endBN_jacobi; } if (BN_cmp(zero,A) > 0) { returnvalue = -1; goto endBN_jacobi; } BN_copy(a1,A); BN_copy(n1,N); startjacobistep1: if (BN_is_zero(a1)) /* step 1 */ goto endBN_jacobi; /* *jacobi = 1; */ if (BN_is_one(a1)) /* step 2 */ goto endBN_jacobi; /* *jacobi = 1; */ for (e=0;;e++) /* step 3 */ if (BN_is_odd(a1)) break; else BN_rshift1(a1,a1); s = 1; /* step 4 */ bit0 = BN_is_odd(n1); bit1 = BN_is_bit_set(n1,1); if (e % 2) { bit2 = BN_is_bit_set(n1,2); if ((!bit2) && (bit1) && (bit0)) s = -1; if ((bit2) && (!bit1) && (bit0)) s = -1; } a1bit0 = BN_is_odd(a1); /* step 5 */ a1bit1 = BN_is_bit_set(a1,1); if (((bit1) && (bit0)) && ((a1bit1) && (a1bit0))) s = -s; BN_mod(n1,n1,a1,ctx); /* step 6 */ BN_copy(tmp,a1); BN_copy(a1,n1); BN_copy(n1,tmp); *jacobi *= s; /* step 7 */ goto startjacobistep1; endBN_jacobi: BN_clear_free(zero); BN_clear_free(tmp);BN_clear_free(a1); BN_clear_free(n1);BN_clear_free(three); return returnvalue; } class BigNum : public Nan::ObjectWrap { public: static void Initialize(Local target); BIGNUM* bignum_; static Nan::Persistent js_conditioner; static void SetJSConditioner(Local constructor); protected: static Nan::Persistent constructor_template; BigNum(const Nan::Utf8String& str, uint64_t base); BigNum(uint64_t num); BigNum(int64_t num); BigNum(BIGNUM *num); BigNum(); ~BigNum(); static NAN_METHOD(New); static NAN_METHOD(ToString); static NAN_METHOD(Badd); static NAN_METHOD(Bsub); static NAN_METHOD(Bmul); static NAN_METHOD(Bdiv); static NAN_METHOD(Uadd); static NAN_METHOD(Usub); static NAN_METHOD(Umul); static NAN_METHOD(Udiv); static NAN_METHOD(Umul_2exp); static NAN_METHOD(Udiv_2exp); static NAN_METHOD(Babs); static NAN_METHOD(Bneg); static NAN_METHOD(Bmod); static NAN_METHOD(Umod); static NAN_METHOD(Bpowm); static NAN_METHOD(Upowm); static NAN_METHOD(Upow); static NAN_METHOD(Uupow); static NAN_METHOD(Brand0); static NAN_METHOD(Uprime0); static NAN_METHOD(Probprime); static NAN_METHOD(Bcompare); static NAN_METHOD(Scompare); static NAN_METHOD(Ucompare); static NAN_METHOD(Band); static NAN_METHOD(Bor); static NAN_METHOD(Bxor); static NAN_METHOD(Binvertm); static NAN_METHOD(Bsqrt); static NAN_METHOD(Broot); static NAN_METHOD(BitLength); static NAN_METHOD(Bgcd); static NAN_METHOD(Bjacobi); static NAN_METHOD(Bsetcompact); static NAN_METHOD(IsBitSet); static Local Bop(Nan::NAN_METHOD_ARGS_TYPE info, int op); }; Nan::Persistent BigNum::constructor_template; Nan::Persistent BigNum::js_conditioner; void BigNum::SetJSConditioner(Local constructor) { js_conditioner.Reset(constructor); } void BigNum::Initialize(v8::Local target) { Nan::HandleScope scope; Local tmpl = Nan::New(New); constructor_template.Reset(tmpl); tmpl->InstanceTemplate()->SetInternalFieldCount(1); tmpl->SetClassName(Nan::New("BigNum").ToLocalChecked()); Nan::SetMethod(tmpl, "uprime0", Uprime0); Nan::SetPrototypeMethod(tmpl, "tostring", ToString); Nan::SetPrototypeMethod(tmpl, "badd", Badd); Nan::SetPrototypeMethod(tmpl, "bsub", Bsub); Nan::SetPrototypeMethod(tmpl, "bmul", Bmul); Nan::SetPrototypeMethod(tmpl, "bdiv", Bdiv); Nan::SetPrototypeMethod(tmpl, "uadd", Uadd); Nan::SetPrototypeMethod(tmpl, "usub", Usub); Nan::SetPrototypeMethod(tmpl, "umul", Umul); Nan::SetPrototypeMethod(tmpl, "udiv", Udiv); Nan::SetPrototypeMethod(tmpl, "umul2exp", Umul_2exp); Nan::SetPrototypeMethod(tmpl, "udiv2exp", Udiv_2exp); Nan::SetPrototypeMethod(tmpl, "babs", Babs); Nan::SetPrototypeMethod(tmpl, "bneg", Bneg); Nan::SetPrototypeMethod(tmpl, "bmod", Bmod); Nan::SetPrototypeMethod(tmpl, "umod", Umod); Nan::SetPrototypeMethod(tmpl, "bpowm", Bpowm); Nan::SetPrototypeMethod(tmpl, "upowm", Upowm); Nan::SetPrototypeMethod(tmpl, "upow", Upow); Nan::SetPrototypeMethod(tmpl, "brand0", Brand0); Nan::SetPrototypeMethod(tmpl, "probprime", Probprime); Nan::SetPrototypeMethod(tmpl, "bcompare", Bcompare); Nan::SetPrototypeMethod(tmpl, "scompare", Scompare); Nan::SetPrototypeMethod(tmpl, "ucompare", Ucompare); Nan::SetPrototypeMethod(tmpl, "band", Band); Nan::SetPrototypeMethod(tmpl, "bor", Bor); Nan::SetPrototypeMethod(tmpl, "bxor", Bxor); Nan::SetPrototypeMethod(tmpl, "binvertm", Binvertm); Nan::SetPrototypeMethod(tmpl, "bsqrt", Bsqrt); Nan::SetPrototypeMethod(tmpl, "broot", Broot); Nan::SetPrototypeMethod(tmpl, "bitLength", BitLength); Nan::SetPrototypeMethod(tmpl, "gcd", Bgcd); Nan::SetPrototypeMethod(tmpl, "jacobi", Bjacobi); Nan::SetPrototypeMethod(tmpl, "setCompact", Bsetcompact); Nan::SetPrototypeMethod(tmpl, "isbitset", IsBitSet); v8::Isolate *isolate = v8::Isolate::GetCurrent(); Nan::Set(target, Nan::New("BigNum").ToLocalChecked(), tmpl->GetFunction(isolate->GetCurrentContext()).ToLocalChecked()); } BigNum::BigNum(const Nan::Utf8String& str, uint64_t base) : Nan::ObjectWrap (), bignum_(BN_new()) { BN_zero(bignum_); BIGNUM *res = bignum_; const char *cstr = *str; switch (base) { case 2: for (int i = 0, l = str.length(); i < l; i++) { if (cstr[l-i-1] != '0') { BN_set_bit(bignum_, i); } } break; case 10: BN_dec2bn(&res, cstr); break; case 16: BN_hex2bn(&res, cstr); break; default: Nan::ThrowError("Invalid base, only 10 and 16 are supported"); return; } } BigNum::BigNum(uint64_t num) : Nan::ObjectWrap (), bignum_(BN_new()) { if (sizeof(BN_ULONG) >= 8 || num <= 0xFFFFFFFFL) { BN_set_word(bignum_, num); } else { BN_set_word(bignum_, num >> 32); BN_lshift(bignum_, bignum_, 32); BN_add_word(bignum_, num & 0xFFFFFFFFL); } } BigNum::BigNum(int64_t num) : Nan::ObjectWrap (), bignum_(BN_new()) { bool neg = (num < 0); if (neg) { num = -num; } if (num < 0) { // num is -2^63 BN_one(bignum_); BN_lshift(bignum_, bignum_, 63); } else if (sizeof(BN_ULONG) >= 8 || num <= 0xFFFFFFFFL) { BN_set_word(bignum_, num); } else { BN_set_word(bignum_, num >> 32); BN_lshift(bignum_, bignum_, 32); BN_add_word(bignum_, num & 0xFFFFFFFFL); } if (neg) { BN_set_negative(bignum_, 1); } } BigNum::BigNum(BIGNUM *num) : Nan::ObjectWrap (), bignum_(BN_new()) { BN_copy(bignum_, num); } BigNum::BigNum() : Nan::ObjectWrap (), bignum_(BN_new()) { BN_zero(bignum_); } BigNum::~BigNum() { BN_clear_free(bignum_); } NAN_METHOD(BigNum::New) { if (!info.IsConstructCall()) { int len = info.Length(); Local* newArgs = new Local[len]; for (int i = 0; i < len; i++) { newArgs[i] = info[i]; } Nan::TryCatch tryCatch; Nan::MaybeLocal newInstMaybeLocal = Nan::NewInstance( Nan::New(constructor_template)->GetFunction(info.GetIsolate()->GetCurrentContext()).ToLocalChecked(), len, newArgs); if (tryCatch.HasCaught()) { tryCatch.ReThrow(); return; } Local newInst = newInstMaybeLocal.ToLocalChecked(); delete[] newArgs; info.GetReturnValue().Set(newInst); return; } BigNum *bignum; uint64_t base; Local currentContext = info.GetIsolate()->GetCurrentContext(); if (info[0]->IsExternal()) { bignum = static_cast(External::Cast(*(info[0]))->Value()); } else { int len = info.Length(); Local ctx = Nan::New(); Local* newArgs = new Local[len]; for (int i = 0; i < len; i++) { newArgs[i] = info[i]; } Local obj; const int ok = Nan::New(js_conditioner)-> Call(currentContext, ctx, info.Length(), newArgs).ToLocal(&obj); delete[] newArgs; if (!ok) { Nan::ThrowError("Invalid type passed to bignum constructor"); return; } Nan::Utf8String str(Nan::Get(obj->ToObject(currentContext).ToLocalChecked(), Nan::New("num").ToLocalChecked()).ToLocalChecked()->ToString(currentContext).ToLocalChecked()); base = Nan::To(Nan::Get(obj->ToObject(currentContext).ToLocalChecked(), Nan::New("base").ToLocalChecked()).ToLocalChecked()).FromJust(); bignum = new BigNum(str, base); } bignum->Wrap(info.This()); info.GetReturnValue().Set(info.This()); } NAN_METHOD(BigNum::ToString) { BigNum *bignum = Nan::ObjectWrap::Unwrap(info.This()); uint64_t base = 10; if (info.Length() > 0) { REQ_UINT64_ARG(0, tbase); base = tbase; } char *to = NULL; switch (base) { case 10: to = BN_bn2dec(bignum->bignum_); break; case 16: to = BN_bn2hex(bignum->bignum_); break; default: Nan::ThrowError("Invalid base, only 10 and 16 are supported"); return; } Local result = Nan::New(to).ToLocalChecked(); OPENSSL_free(to); info.GetReturnValue().Set(result); } NAN_METHOD(BigNum::Badd) { BigNum *bignum = Nan::ObjectWrap::Unwrap(info.This()); BigNum *bn = Nan::ObjectWrap::Unwrap(info[0]->ToObject(info.GetIsolate()->GetCurrentContext()).ToLocalChecked()); BigNum *res = new BigNum(); BN_add(res->bignum_, bignum->bignum_, bn->bignum_); WRAP_RESULT(res, result); info.GetReturnValue().Set(result); } NAN_METHOD(BigNum::Bsub) { BigNum *bignum = Nan::ObjectWrap::Unwrap(info.This()); BigNum *bn = Nan::ObjectWrap::Unwrap(info[0]->ToObject(info.GetIsolate()->GetCurrentContext()).ToLocalChecked()); BigNum *res = new BigNum(); BN_sub(res->bignum_, bignum->bignum_, bn->bignum_); WRAP_RESULT(res, result); info.GetReturnValue().Set(result); } NAN_METHOD(BigNum::Bmul) { AutoBN_CTX ctx; BigNum *bignum = Nan::ObjectWrap::Unwrap(info.This()); BigNum *bn = Nan::ObjectWrap::Unwrap(info[0]->ToObject(info.GetIsolate()->GetCurrentContext()).ToLocalChecked()); BigNum *res = new BigNum(); BN_mul(res->bignum_, bignum->bignum_, bn->bignum_, ctx); WRAP_RESULT(res, result); info.GetReturnValue().Set(result); } NAN_METHOD(BigNum::Bdiv) { AutoBN_CTX ctx; BigNum *bignum = Nan::ObjectWrap::Unwrap(info.This()); BigNum *bi = Nan::ObjectWrap::Unwrap(info[0]->ToObject(info.GetIsolate()->GetCurrentContext()).ToLocalChecked()); BigNum *res = new BigNum(); BN_div(res->bignum_, NULL, bignum->bignum_, bi->bignum_, ctx); WRAP_RESULT(res, result); info.GetReturnValue().Set(result); } NAN_METHOD(BigNum::Uadd) { BigNum *bignum = Nan::ObjectWrap::Unwrap(info.This()); REQ_UINT64_ARG(0, x); BigNum *res = new BigNum(bignum->bignum_); if (sizeof(BN_ULONG) >= 8 || x <= 0xFFFFFFFFL) { BN_add_word(res->bignum_, x); } else { BigNum *bn = new BigNum(x); BN_add(res->bignum_, bignum->bignum_, bn->bignum_); } WRAP_RESULT(res, result); info.GetReturnValue().Set(result); } NAN_METHOD(BigNum::Usub) { BigNum *bignum = Nan::ObjectWrap::Unwrap(info.This()); REQ_UINT64_ARG(0, x); BigNum *res = new BigNum(bignum->bignum_); if (sizeof(BN_ULONG) >= 8 || x <= 0xFFFFFFFFL) { BN_sub_word(res->bignum_, x); } else { BigNum *bn = new BigNum(x); BN_sub(res->bignum_, bignum->bignum_, bn->bignum_); } WRAP_RESULT(res, result); info.GetReturnValue().Set(result); } NAN_METHOD(BigNum::Umul) { BigNum *bignum = Nan::ObjectWrap::Unwrap(info.This()); REQ_UINT64_ARG(0, x); BigNum *res = new BigNum(bignum->bignum_); if (sizeof(BN_ULONG) >= 8 || x <= 0xFFFFFFFFL) { BN_mul_word(res->bignum_, x); } else { AutoBN_CTX ctx; BigNum *bn = new BigNum(x); BN_mul(res->bignum_, bignum->bignum_, bn->bignum_, ctx); } WRAP_RESULT(res, result); info.GetReturnValue().Set(result); } NAN_METHOD(BigNum::Udiv) { BigNum *bignum = Nan::ObjectWrap::Unwrap(info.This()); REQ_UINT64_ARG(0, x); BigNum *res = new BigNum(bignum->bignum_); if (sizeof(BN_ULONG) >= 8 || x <= 0xFFFFFFFFL) { BN_div_word(res->bignum_, x); } else { AutoBN_CTX ctx; BigNum *bn = new BigNum(x); BN_div(res->bignum_, NULL, bignum->bignum_, bn->bignum_, ctx); } WRAP_RESULT(res, result); info.GetReturnValue().Set(result); } NAN_METHOD(BigNum::Umul_2exp) { BigNum *bignum = Nan::ObjectWrap::Unwrap(info.This()); REQ_UINT32_ARG(0, x); BigNum *res = new BigNum(); BN_lshift(res->bignum_, bignum->bignum_, x); WRAP_RESULT(res, result); info.GetReturnValue().Set(result); } NAN_METHOD(BigNum::Udiv_2exp) { BigNum *bignum = Nan::ObjectWrap::Unwrap(info.This()); REQ_UINT32_ARG(0, x); BigNum *res = new BigNum(); BN_rshift(res->bignum_, bignum->bignum_, x); WRAP_RESULT(res, result); info.GetReturnValue().Set(result); } NAN_METHOD(BigNum::Babs) { BigNum *bignum = Nan::ObjectWrap::Unwrap(info.This()); BigNum *res = new BigNum(bignum->bignum_); BN_set_negative(res->bignum_, 0); WRAP_RESULT(res, result); info.GetReturnValue().Set(result); } NAN_METHOD(BigNum::Bneg) { BigNum *bignum = Nan::ObjectWrap::Unwrap(info.This()); BigNum *res = new BigNum(bignum->bignum_); BN_set_negative(res->bignum_, !BN_is_negative(res->bignum_)); WRAP_RESULT(res, result); info.GetReturnValue().Set(result); } NAN_METHOD(BigNum::Bmod) { AutoBN_CTX ctx; BigNum *bignum = Nan::ObjectWrap::Unwrap(info.This()); BigNum *bn = Nan::ObjectWrap::Unwrap(info[0]->ToObject(info.GetIsolate()->GetCurrentContext()).ToLocalChecked()); BigNum *res = new BigNum(); BN_div(NULL, res->bignum_, bignum->bignum_, bn->bignum_, ctx); WRAP_RESULT(res, result); info.GetReturnValue().Set(result); } NAN_METHOD(BigNum::Umod) { BigNum *bignum = Nan::ObjectWrap::Unwrap(info.This()); REQ_UINT64_ARG(0, x); BigNum *res = new BigNum(); if (sizeof(BN_ULONG) >= 8 || x <= 0xFFFFFFFFL) { BN_set_word(res->bignum_, BN_mod_word(bignum->bignum_, x)); } else { AutoBN_CTX ctx; BigNum *bn = new BigNum(x); BN_div(NULL, res->bignum_, bignum->bignum_, bn->bignum_, ctx); } WRAP_RESULT(res, result); info.GetReturnValue().Set(result); } NAN_METHOD(BigNum::Bpowm) { AutoBN_CTX ctx; BigNum *bignum = Nan::ObjectWrap::Unwrap(info.This()); BigNum *bn1 = Nan::ObjectWrap::Unwrap(info[0]->ToObject(info.GetIsolate()->GetCurrentContext()).ToLocalChecked()); BigNum *bn2 = Nan::ObjectWrap::Unwrap(info[1]->ToObject(info.GetIsolate()->GetCurrentContext()).ToLocalChecked()); BigNum *res = new BigNum(); BN_mod_exp(res->bignum_, bignum->bignum_, bn1->bignum_, bn2->bignum_, ctx); WRAP_RESULT(res, result); info.GetReturnValue().Set(result); } NAN_METHOD(BigNum::Upowm) { AutoBN_CTX ctx; BigNum *bignum = Nan::ObjectWrap::Unwrap(info.This()); REQ_UINT64_ARG(0, x); BigNum *bn = Nan::ObjectWrap::Unwrap(info[1]->ToObject(info.GetIsolate()->GetCurrentContext()).ToLocalChecked()); BigNum *exp = new BigNum(x); BigNum *res = new BigNum(); BN_mod_exp(res->bignum_, bignum->bignum_, exp->bignum_, bn->bignum_, ctx); WRAP_RESULT(res, result); info.GetReturnValue().Set(result); } NAN_METHOD(BigNum::Upow) { AutoBN_CTX ctx; BigNum *bignum = Nan::ObjectWrap::Unwrap(info.This()); REQ_UINT64_ARG(0, x); BigNum *exp = new BigNum(x); BigNum *res = new BigNum(); BN_exp(res->bignum_, bignum->bignum_, exp->bignum_, ctx); WRAP_RESULT(res, result); info.GetReturnValue().Set(result); } NAN_METHOD(BigNum::Brand0) { BigNum *bignum = Nan::ObjectWrap::Unwrap(info.This()); BigNum *res = new BigNum(); BN_rand_range(res->bignum_, bignum->bignum_); WRAP_RESULT(res, result); info.GetReturnValue().Set(result); } NAN_METHOD(BigNum::Uprime0) { REQ_UINT32_ARG(0, x); REQ_BOOL_ARG(1, safe); BigNum *res = new BigNum(); BN_generate_prime_ex(res->bignum_, x, safe, NULL, NULL, NULL); WRAP_RESULT(res, result); info.GetReturnValue().Set(result); } NAN_METHOD(BigNum::Probprime) { AutoBN_CTX ctx; BigNum *bignum = Nan::ObjectWrap::Unwrap(info.This()); REQ_UINT32_ARG(0, reps); info.GetReturnValue().Set(Nan::New(BN_is_prime_ex(bignum->bignum_, reps, ctx, NULL))); } NAN_METHOD(BigNum::IsBitSet) { BigNum *bignum = Nan::ObjectWrap::Unwrap(info.This()); REQ_UINT32_ARG(0, n); info.GetReturnValue().Set(Nan::New(BN_is_bit_set(bignum->bignum_, n))); } NAN_METHOD(BigNum::Bcompare) { BigNum *bignum = Nan::ObjectWrap::Unwrap(info.This()); BigNum *bn = Nan::ObjectWrap::Unwrap(info[0]->ToObject(info.GetIsolate()->GetCurrentContext()).ToLocalChecked()); info.GetReturnValue().Set(Nan::New(BN_cmp(bignum->bignum_, bn->bignum_))); } NAN_METHOD(BigNum::Scompare) { BigNum *bignum = Nan::ObjectWrap::Unwrap(info.This()); REQ_INT64_ARG(0, x); BigNum *bn = new BigNum(x); int res = BN_cmp(bignum->bignum_, bn->bignum_); info.GetReturnValue().Set(Nan::New(res)); } NAN_METHOD(BigNum::Ucompare) { BigNum *bignum = Nan::ObjectWrap::Unwrap(info.This()); REQ_UINT64_ARG(0, x); int res; if (sizeof(BN_ULONG) >= 8 || x <= 0xFFFFFFFFL) { BIGNUM* bn = BN_new(); BN_set_word(bn, x); res = BN_cmp(bignum->bignum_, bn); BN_clear_free(bn); } else { BigNum *bn = new BigNum(x); res = BN_cmp(bignum->bignum_, bn->bignum_); } info.GetReturnValue().Set(Nan::New(res)); } // Utility functions from converting OpenSSL's MPI // format to two's complement, which is what bitwise // operations are expected to work on static void mpi2twosComplement(uint8_t *bytes, size_t numBytes) { int i; bytes[0] &= ~0x80; for (i = 0; i < (int) numBytes; i++) { bytes[i] = ~bytes[i]; } for (i = numBytes - 1; i >= 0; i--) { if (bytes[i] == 0xff) { bytes[i] = 0; } else { bytes[i]++; break; } } } static void twos_complement2mpi(uint8_t *bytes, size_t numBytes) { int i; for (i = numBytes - 1; i >= 0; i--) { if (bytes[i] == 0) { bytes[i] = 0xff; } else { bytes[i]--; break; } } for (i = 0; i < (int) numBytes; i++) { bytes[i] = ~bytes[i]; } bytes[0] |= 0x80; } const int BN_PAYLOAD_OFFSET = 4; // Shifts things around in an OpenSSL MPI buffer so that // the sizes of bignum operands match static void shiftSizeAndMSB(uint8_t *bytes, uint8_t *sizeBuffer, size_t offset) { memset(bytes + offset, 0, BN_PAYLOAD_OFFSET); memcpy(bytes, sizeBuffer, BN_PAYLOAD_OFFSET); // We've copied the size header over; now we just need to move // the MSB signifying negativity if it's present if(bytes[BN_PAYLOAD_OFFSET + offset] & 0x80) { bytes[BN_PAYLOAD_OFFSET] |= 0x80; bytes[BN_PAYLOAD_OFFSET + offset] &= ~0x80; } } static bool isMinimumNegativeNumber(uint8_t *bytes, size_t size) { if (bytes[0] != 0x80) { return false; } for (size_t i = 1; i < size; i++) { if (bytes[i] != 0) { return false; } } return true; } static void swapEndianness(uint8_t *bytes) { uint8_t tmp; tmp = bytes[0]; bytes[0] = bytes[3]; bytes[3] = tmp; tmp = bytes[1]; bytes[1] = bytes[2]; bytes[2] = tmp; } Local BigNum::Bop(Nan::NAN_METHOD_ARGS_TYPE info, int op) { Nan::EscapableHandleScope scope; BigNum *bignum = Nan::ObjectWrap::Unwrap(info.This()); BigNum *bn = Nan::ObjectWrap::Unwrap(info[0]->ToObject(info.GetIsolate()->GetCurrentContext()).ToLocalChecked()); bool bignumNegative = BN_is_negative(bignum->bignum_); bool bnNegative = BN_is_negative(bn->bignum_); BigNum *res = new BigNum(); // Modified from https://github.com/Worlize/WebSocket-Node/blob/master/src/xor.cpp // Portions Copyright (c) Agora S.A. // Licensed under the MIT License. int payloadSize = BN_bn2mpi(bignum->bignum_, NULL); int maskSize = BN_bn2mpi(bn->bignum_, NULL); uint32_t size = max(payloadSize, maskSize); int offset = abs(payloadSize - maskSize); int payloadOffset = 0; int maskOffset = 0; if (payloadSize < maskSize) { payloadOffset = offset; } else if (payloadSize > maskSize) { maskOffset = offset; } uint8_t* payload = (uint8_t*) calloc(size, sizeof(char)); uint8_t* mask = (uint8_t*) calloc(size, sizeof(char)); BN_bn2mpi(bignum->bignum_, payload + payloadOffset); BN_bn2mpi(bn->bignum_, mask + maskOffset); if (payloadSize < maskSize) { shiftSizeAndMSB(payload, mask, payloadOffset); } else { shiftSizeAndMSB(mask, payload, maskOffset); } payload += BN_PAYLOAD_OFFSET; mask += BN_PAYLOAD_OFFSET; size -= BN_PAYLOAD_OFFSET; if(bignumNegative) { mpi2twosComplement(payload, size); } if(bnNegative) { mpi2twosComplement(mask, size); } uint32_t* pos32 = (uint32_t*) payload; uint32_t* end32 = pos32 + (size / 4); uint32_t* mask32 = (uint32_t*) mask; switch (op) { case 0: while (pos32 < end32) *(pos32++) &= *(mask32++); break; case 1: while (pos32 < end32) *(pos32++) |= *(mask32++); break; case 2: while (pos32 < end32) *(pos32++) ^= *(mask32++); break; } uint8_t* pos8 = (uint8_t*) pos32; uint8_t* end8 = payload + size; uint8_t* mask8 = (uint8_t*) mask32; switch (op) { case 0: while (pos8 < end8) *(pos8++) &= *(mask8++); break; case 1: while (pos8 < end8) *(pos8++) |= *(mask8++); break; case 2: while (pos8 < end8) *(pos8++) ^= *(mask8++); break; } payload -= BN_PAYLOAD_OFFSET; mask -= BN_PAYLOAD_OFFSET; size += BN_PAYLOAD_OFFSET; // If the value is the largest negative number representible by // size bytes, we need to add another byte to the payload buffer, // otherwise OpenSSL's BN_mpi2bn will interpret the number as -0 if (isMinimumNegativeNumber(payload + BN_PAYLOAD_OFFSET, size - BN_PAYLOAD_OFFSET)) { bool bigEndian = (size - BN_PAYLOAD_OFFSET) == *((uint32_t *) payload); uint8_t *newPayload = (uint8_t *) calloc(size + 1, 1); memcpy(newPayload + 5, payload + BN_PAYLOAD_OFFSET, size - BN_PAYLOAD_OFFSET); newPayload[BN_PAYLOAD_OFFSET] = 0x80; size++; size -= BN_PAYLOAD_OFFSET; memcpy(newPayload, &size, BN_PAYLOAD_OFFSET); size += BN_PAYLOAD_OFFSET; if (!bigEndian) { swapEndianness(newPayload); } free(payload); payload = newPayload; } else if(payload[BN_PAYLOAD_OFFSET] & 0x80) { twos_complement2mpi(payload + BN_PAYLOAD_OFFSET, size - BN_PAYLOAD_OFFSET); } BN_mpi2bn(payload, size, res->bignum_); WRAP_RESULT(res, result); free(payload); free(mask); return scope.Escape(result); } NAN_METHOD(BigNum::Band) { info.GetReturnValue().Set(Bop(info, 0)); } NAN_METHOD(BigNum::Bor) { info.GetReturnValue().Set(Bop(info, 1)); } NAN_METHOD(BigNum::Bxor) { info.GetReturnValue().Set(Bop(info, 2)); } NAN_METHOD(BigNum::Binvertm) { AutoBN_CTX ctx; BigNum *bignum = Nan::ObjectWrap::Unwrap(info.This()); BigNum *bn = Nan::ObjectWrap::Unwrap(info[0]->ToObject(info.GetIsolate()->GetCurrentContext()).ToLocalChecked()); BigNum *res = new BigNum(); BN_mod_inverse(res->bignum_, bignum->bignum_, bn->bignum_, ctx); WRAP_RESULT(res, result); info.GetReturnValue().Set(result); } NAN_METHOD(BigNum::Bsqrt) { Nan::ThrowError("sqrt is not supported by OpenSSL."); } NAN_METHOD(BigNum::Broot) { Nan::ThrowError("root is not supported by OpenSSL."); } NAN_METHOD(BigNum::BitLength) { BigNum *bignum = Nan::ObjectWrap::Unwrap(info.This()); int size = BN_num_bits(bignum->bignum_); Local result = Nan::New(size); info.GetReturnValue().Set(result); } NAN_METHOD(BigNum::Bgcd) { AutoBN_CTX ctx; BigNum *bignum = Nan::ObjectWrap::Unwrap(info.This()); BigNum *bi = Nan::ObjectWrap::Unwrap(info[0]->ToObject(info.GetIsolate()->GetCurrentContext()).ToLocalChecked()); BigNum *res = new BigNum(); BN_gcd(res->bignum_, bignum->bignum_, bi->bignum_, ctx); WRAP_RESULT(res, result); info.GetReturnValue().Set(result); } NAN_METHOD(BigNum::Bjacobi) { AutoBN_CTX ctx; BigNum *bn_a = Nan::ObjectWrap::Unwrap(info.This()); BigNum *bn_n = Nan::ObjectWrap::Unwrap(info[0]->ToObject(info.GetIsolate()->GetCurrentContext()).ToLocalChecked()); int res = 0; if (BN_jacobi_priv(bn_a->bignum_, bn_n->bignum_, &res, ctx) == -1) { Nan::ThrowError("Jacobi symbol calculation failed"); return; } info.GetReturnValue().Set(Nan::New(res)); } NAN_METHOD(BigNum::Bsetcompact) { BigNum *bignum = Nan::ObjectWrap::Unwrap(info.This()); unsigned int nCompact = Nan::To(info[0]).FromJust(); unsigned int nSize = nCompact >> 24; bool fNegative =(nCompact & 0x00800000) != 0; unsigned int nWord = nCompact & 0x007fffff; if (nSize <= 3) { nWord >>= 8*(3-nSize); BN_set_word(bignum->bignum_, nWord); } else { BN_set_word(bignum->bignum_, nWord); BN_lshift(bignum->bignum_, bignum->bignum_, 8*(nSize-3)); } BN_set_negative(bignum->bignum_, fNegative); info.GetReturnValue().Set(info.This()); } static NAN_METHOD(SetJSConditioner) { Nan::HandleScope scope; BigNum::SetJSConditioner(Local::Cast(info[0])); return; } extern "C" void init (Local target) { Nan::HandleScope scope; BigNum::Initialize(target); Nan::SetMethod(target, "setJSConditioner", SetJSConditioner); } NODE_MODULE(bignum, init) ================================================ FILE: binding.gyp ================================================ { 'targets': [ { 'target_name': 'bignum', 'sources': [ 'bignum.cc' ], 'include_dirs': [ " 2**159') assert.ok(q.lt(bignum.pow(2, 160)), 'q < 2**160') assert.ok(p.gt(bignum.pow(2, L - 1)), 'p > 2**(L-1)') assert.ok(q.lt(bignum.pow(2, L)), 'p < 2**L') assert.ok(q.mul(p.sub(1).div(q)).add(1).eq(p), 'q divides p - 1') assert.ok(p.probPrime(50), 'p is not prime!') assert.ok(q.probPrime(50), 'q is not prime!') console.dir({ p: p, q: q }) ================================================ FILE: examples/perfect.js ================================================ // If 2**n-1 is prime, then (2**n-1) * 2**(n-1) is perfect. var bignum = require('../') for (var n = 0; n < 100; n++) { var p = bignum.pow(2, n).sub(1) if (p.probPrime(50)) { var perfect = p.mul(bignum.pow(2, n - 1)) console.log(perfect.toString()) } } ================================================ FILE: examples/simple.js ================================================ var bignum = require('../') var b = bignum('782910138827292261791972728324982') .sub('182373273283402171237474774728373') .div(8) console.log(b) ================================================ FILE: index.js ================================================ var bin = require('bindings')('bignum') var Buffer = require('safe-buffer').Buffer var BigNum = bin.BigNum module.exports = BigNum BigNum.conditionArgs = function (num, base) { if (typeof num !== 'string') num = num.toString(base || 10) if (num.match(/e\+/)) { // positive exponent if (!Number(num).toString().match(/e+/)) { return { num: Math.floor(Number(num)).toString(), base: 10 } } else { var pow = Math.ceil(Math.log(num) / Math.log(2)) var n = (num / Math.pow(2, pow)).toString(2) .replace(/^0/, '') var i = n.length - n.indexOf('.') n = n.replace(/\./, '') for (; i <= pow; i++) n += '0' return { num: n, base: 2 } } } else if (num.match(/e-/)) { // negative exponent return { num: Math.floor(Number(num)).toString(), base: base || 10 } } else { return { num: num, base: base || 10 } } } bin.setJSConditioner(BigNum.conditionArgs) BigNum.isBigNum = function (num) { if (!num) { return false } for (var key in BigNum.prototype) { if (!num[key]) { return false } } return true } BigNum.prototype.inspect = function () { return '' } BigNum.prototype.toString = function (base) { var value if (base) { value = this.tostring(base) } else { value = this.tostring() } if (base > 10 && typeof value === 'string') { value = value.toLowerCase() } return value } BigNum.prototype.toNumber = function () { return parseInt(this.toString(), 10) } ;['add', 'sub', 'mul', 'div', 'mod'].forEach(function (op) { BigNum.prototype[op] = function (num) { var x if (BigNum.isBigNum(num)) { return this['b' + op](num) } else if (typeof num === 'number') { if (num >= 0) { return this['u' + op](num) } else if (op === 'add') { return this.usub(-num) } else if (op === 'sub') { return this.uadd(-num) } else { x = BigNum(num) return this['b' + op](x) } } else if (typeof num === 'string') { x = BigNum(num) return this['b' + op](x) } else { throw new TypeError('Unspecified operation for type ' + (typeof num) + ' for ' + op) } } }) BigNum.prototype.abs = function () { return this.babs() } BigNum.prototype.neg = function () { return this.bneg() } BigNum.prototype.powm = function (num, mod) { var m if ((typeof mod) === 'number' || (typeof mod) === 'string') { m = BigNum(mod) } else if (BigNum.isBigNum(mod)) { m = mod } if ((typeof num) === 'number') { return this.upowm(num, m) } else if ((typeof num) === 'string') { var n = BigNum(num) return this.bpowm(n, m) } else if (BigNum.isBigNum(num)) { return this.bpowm(num, m) } } BigNum.prototype.mod = function (num, mod) { var m if ((typeof mod) === 'number' || (typeof mod) === 'string') { m = BigNum(mod) } else if (BigNum.isBigNum(mod)) { m = mod } if ((typeof num) === 'number') { return this.umod(num, m) } else if ((typeof num) === 'string') { var n = BigNum(num) return this.bmod(n, m) } else if (BigNum.isBigNum(num)) { return this.bmod(num, m) } } BigNum.prototype.pow = function (num) { if (typeof num === 'number') { if (num >= 0) { return this.upow(num) } else { return BigNum.prototype.powm.call(this, num, this) } } else { var x = parseInt(num.toString(), 10) return BigNum.prototype.pow.call(this, x) } } BigNum.prototype.shiftLeft = function (num) { if (typeof num === 'number') { if (num >= 0) { return this.umul2exp(num) } else { return this.shiftRight(-num) } } else { var x = parseInt(num.toString(), 10) return BigNum.prototype.shiftLeft.call(this, x) } } BigNum.prototype.shiftRight = function (num) { if (typeof num === 'number') { if (num >= 0) { return this.udiv2exp(num) } else { return this.shiftLeft(-num) } } else { var x = parseInt(num.toString(), 10) return BigNum.prototype.shiftRight.call(this, x) } } BigNum.prototype.cmp = function (num) { if (BigNum.isBigNum(num)) { return this.bcompare(num) } else if (typeof num === 'number') { if (num < 0) { return this.scompare(num) } else { return this.ucompare(num) } } else { var x = BigNum(num) return this.bcompare(x) } } BigNum.prototype.gt = function (num) { return this.cmp(num) > 0 } BigNum.prototype.ge = function (num) { return this.cmp(num) >= 0 } BigNum.prototype.eq = function (num) { return this.cmp(num) === 0 } BigNum.prototype.ne = function (num) { return this.cmp(num) !== 0 } BigNum.prototype.lt = function (num) { return this.cmp(num) < 0 } BigNum.prototype.le = function (num) { return this.cmp(num) <= 0 } 'and or xor'.split(' ').forEach(function (name) { BigNum.prototype[name] = function (num) { if (BigNum.isBigNum(num)) { return this['b' + name](num) } else { var x = BigNum(num) return this['b' + name](x) } } }) BigNum.prototype.sqrt = function () { return this.bsqrt() } BigNum.prototype.root = function (num) { if (BigNum.isBigNum(num)) { return this.broot(num) } else { return this.broot(num) } } BigNum.prototype.rand = function (to) { if (to === undefined) { if (this.toString() === '1') { return BigNum(0) } else { return this.brand0() } } else { var x = BigNum.isBigNum(to) ? to.sub(this) : BigNum(to).sub(this) return x.brand0().add(this) } } BigNum.prototype.invertm = function (mod) { if (BigNum.isBigNum(mod)) { return this.binvertm(mod) } else { var x = BigNum(mod) return this.binvertm(x) } } BigNum.prime = function (bits, safe) { if (typeof safe === 'undefined') { safe = true } // Force uint32 bits >>>= 0 return BigNum.uprime0(bits, !!safe) } BigNum.prototype.probPrime = function (reps) { var n = this.probprime(reps || 10) return { 1: true, 0: false }[n] } BigNum.prototype.nextPrime = function () { var num = this do { num = num.add(1) } while (!num.probPrime()) return num } BigNum.prototype.isBitSet = function (n) { return this.isbitset(n) === 1 } BigNum.fromBuffer = function (buf, opts) { if (!opts) opts = {} var endian = { 1: 'big', '-1': 'little' }[opts.endian] || opts.endian || 'big' var size = opts.size === 'auto' ? Math.ceil(buf.length) : (opts.size || 1) if (buf.length % size !== 0) { throw new RangeError('Buffer length (' + buf.length + ')' + ' must be a multiple of size (' + size + ')' ) } var hex = [] for (var i = 0; i < buf.length; i += size) { var chunk = [] for (var j = 0; j < size; j++) { chunk.push(buf[i + (endian === 'big' ? j : (size - j - 1))]) } hex.push(chunk .map(function (c) { return (c < 16 ? '0' : '') + c.toString(16) }) .join('') ) } return BigNum(hex.join(''), 16) } BigNum.prototype.toBuffer = function (opts) { if (typeof opts === 'string') { if (opts !== 'mpint') return 'Unsupported Buffer representation' var abs = this.abs() var buf = abs.toBuffer({ size: 1, endian: 'big' }) var len = buf.length === 1 && buf[0] === 0 ? 0 : buf.length if (buf[0] & 0x80) len++ var ret = Buffer.alloc(4 + len) if (len > 0) buf.copy(ret, 4 + (buf[0] & 0x80 ? 1 : 0)) if (buf[0] & 0x80) ret[4] = 0 ret[0] = len & (0xff << 24) ret[1] = len & (0xff << 16) ret[2] = len & (0xff << 8) ret[3] = len & (0xff << 0) // two's compliment for negative integers: var isNeg = this.lt(0) if (isNeg) { for (var i = 4; i < ret.length; i++) { ret[i] = 0xff - ret[i] } } ret[4] = (ret[4] & 0x7f) | (isNeg ? 0x80 : 0) if (isNeg) ret[ret.length - 1]++ return ret } if (!opts) opts = {} var endian = { 1: 'big', '-1': 'little' }[opts.endian] || opts.endian || 'big' var hex = this.toString(16) if (hex.charAt(0) === '-') { throw new Error('converting negative numbers to Buffers not supported yet') } var size = opts.size === 'auto' ? Math.ceil(hex.length / 2) : (opts.size || 1) len = Math.ceil(hex.length / (2 * size)) * size buf = Buffer.alloc(len) // zero-pad the hex string so the chunks are all `size` long while (hex.length < 2 * len) hex = '0' + hex var hx = hex .split(new RegExp('(.{' + (2 * size) + '})')) .filter(function (s) { return s.length > 0 }) hx.forEach(function (chunk, i) { for (var j = 0; j < size; j++) { var ix = i * size + (endian === 'big' ? j : size - j - 1) buf[ix] = parseInt(chunk.slice(j * 2, j * 2 + 2), 16) } }) return buf } Object.keys(BigNum.prototype).forEach(function (name) { if (name === 'inspect' || name === 'toString') return BigNum[name] = function (num) { var args = [].slice.call(arguments, 1) if (BigNum.isBigNum(num)) { return num[name].apply(num, args) } else { var bigi = BigNum(num) return bigi[name].apply(bigi, args) } } }) ================================================ FILE: package.json ================================================ { "name": "bignum", "version": "0.13.1", "description": "Arbitrary-precision integer arithmetic using OpenSSL", "main": "./index.js", "repository": { "type": "git", "url": "http://github.com/justmoon/node-bignum.git" }, "keywords": [ "openssl", "big", "bignum", "bigint", "integer", "arithmetic", "precision" ], "author": { "name": "Stefan Thomas", "email": "justmoon@members.fsf.org", "url": "http://www.justmoon.net" }, "dependencies": { "bindings": "^1.5.0", "nan": "^2.14.0", "safe-buffer": "^5.2.0" }, "devDependencies": { "put": "0.0.6", "standard": "^14.3.1", "tap": "^14.10.5" }, "scripts": { "install": "node-gyp rebuild", "test": "standard && tap --timeout 120 test/*.js" }, "license": "MIT", "contributors": [ "James Halliday ", "Rod Vagg " ] } ================================================ FILE: test/big.js ================================================ var Buffer = require('safe-buffer').Buffer var BigNum = require('../') var test = require('tap').test test('create', { timeout: 120000 }, function (t) { t.deepEqual(BigNum(1337).toString(), '1337') t.deepEqual(BigNum('1337').toString(), '1337') t.deepEqual(new BigNum('100').toString(), '100') t.deepEqual( new BigNum('55555555555555555555555555').toString(), '55555555555555555555555555' ) t.deepEqual(Number(BigNum('1e+100').toString()), 1e+100) t.deepEqual(Number(BigNum('1e+100').bitLength()), 333) t.deepEqual(Number(BigNum('1.23e+45').toString()), 1.23e+45) for (var i = 0; i < 10; i++) { t.deepEqual( BigNum('1.23456e+' + i).toString(), Math.floor(1.23456 * Math.pow(10, i)) ) } t.deepEqual(BigNum('1.23e-45').toString(), '0') t.throws(function () { BigNum(undefined) }) t.throws(function () { BigNum(null) }) t.end() }) test('add', { timeout: 120000 }, function (t) { for (var i = -10; i < 10; i++) { for (var j = -10; j < 10; j++) { var js = j.toString() var ks = (i + j).toString() t.deepEqual(BigNum(i).add(j).toString(), ks) t.deepEqual(BigNum(i).add(js).toString(), ks) t.deepEqual(BigNum(i).add(BigNum(j)).toString(), ks) t.deepEqual(BigNum.add(i, j).toString(), ks) } } t.deepEqual( BigNum( '201781752444966478956292456789265633588628356858680927185287861892' + '9889675589272409635031813235465496971529430565627918846694860512' + '1492948268400884893722767401972695174353441' ).add( '939769862972759638577945343130228368606420083646071622223953046277' + '3784500359975110887672142614667937014937371109558223563373329424' + '0624814097369771481147215472578762824607080' ).toString(), '1141551615417726117534237799919494002195048440504752549409240908170367' + '41759492475205227039558501334339864668016751861424100681899362117762' + '365770656374869982874551457998960521' ) t.end() }) test('sub', { timeout: 120000 }, function (t) { for (var i = -10; i < 10; i++) { for (var j = -10; j < 10; j++) { var js = j.toString() var ks = (i - j).toString() t.deepEqual(BigNum(i).sub(j).toString(), ks) t.deepEqual(BigNum(i).sub(js).toString(), ks) t.deepEqual(BigNum(i).sub(BigNum(j)).toString(), ks) t.deepEqual(BigNum.sub(i, j).toString(), ks) } } t.deepEqual( BigNum( '635849762218952604062459342660379446997761295162166888134051068531' + '9813941775949841573516110003093332652267534768664621969514455380' + '8051168706779408804756208386011014197185296' ).sub( '757617343536280696839135295661092954931163607913400460585109207644' + '7966483882748233585856350085641718822741649072106343655764769889' + '6399869016678013515043471880323279258685478' ).toString(), '-121767581317328092776675953000713507933402312751233572451058139112815' + '25421067983920123402400825483861704741143034417216862503145088348700' + '309898604710287263494312265061500182' ) t.end() }) test('mul', { timeout: 120000 }, function (t) { for (var i = -10; i < 10; i++) { for (var j = -10; j < 10; j++) { var js = j.toString() var ks = (i * j).toString() t.deepEqual(BigNum(i).mul(j).toString(), ks) t.deepEqual(BigNum(i).mul(js).toString(), ks) t.deepEqual(BigNum(i).mul(BigNum(j)).toString(), ks) t.deepEqual(BigNum.mul(i, j).toString(), ks) } } t.deepEqual( BigNum( '433593290010590489671135819286259593426549306666324008679782084292' + '2446494189019075159822930571858728009485237489829138626896756141' + '8738958337632249177044975686477011571044266' ).mul( '127790264841901718791915669264129510947625523373763053776083279450' + '3886212911067061184379695097643279217271150419129022856601771338' + '794256383410400076210073482253089544155377' ).toString(), '5540900136412485758752141142221047463857522755277604708501015732755989' + '17659432099233635577634197309727815375309484297883528869192732141328' + '99346769031695550850320602049507618052164677667378189154076988316301' + '23719953859959804490669091769150047414629675184805332001182298088891' + '58079529848220802017396422115936618644438110463469902675126288489182' + '82' ) t.deepEqual( BigNum('10000000000000000000000000000').mul(-123).toString(), '-1230000000000000000000000000000' ) t.end() }) test('div', { timeout: 120000 }, function (t) { for (var i = -10; i < 10; i++) { for (var j = -10; j < 10; j++) { var js = j.toString() var round = ((i / j) < 0) ? Math.ceil : Math.floor var ks = round(i / j).toString() if (ks.match(/^-?\d+$/)) { // ignore exceptions t.deepEqual(BigNum(i).div(j).toString(), ks) t.deepEqual(BigNum(i).div(js).toString(), ks) t.deepEqual(BigNum(i).div(BigNum(j)).toString(), ks) t.deepEqual(BigNum.div(i, j).toString(), ks) } } } t.deepEqual( BigNum( '433593290010590489671135819286259593426549306666324008679782084292' + '2446494189019075159822930571858728009485237489829138626896756141' + '8738958337632249177044975686477011571044266' ).div( '127790264841901718791915669264129510947625523373763053776083279450' + '3886212911067061184379695097643279217271150419129022856601771338' + '794256383410400076210073482253089544155377' ).toString(), '33' ) t.end() }) test('abs', { timeout: 120000 }, function (t) { t.deepEqual( BigNum( '433593290010590489671135819286259593426549306666324008679782084292' + '2446494189019075159822930571858728009485237489829138626896756141' + '8738958337632249177044975686477011571044266' ).abs().toString(), '4335932900105904896711358192862595934265493066663240086797820842922446' + '49418901907515982293057185872800948523748982913862689675614187389583' + '37632249177044975686477011571044266' ) t.deepEqual( BigNum( '-43359329001059048967113581928625959342654930666632400867978208429' + '2244649418901907515982293057185872800948523748982913862689675614' + '18738958337632249177044975686477011571044266' ).abs().toString(), '4335932900105904896711358192862595934265493066663240086797820842922446' + '49418901907515982293057185872800948523748982913862689675614187389583' + '37632249177044975686477011571044266' ) t.end() }) test('neg', { timeout: 120000 }, function (t) { t.deepEqual( BigNum( '433593290010590489671135819286259593426549306666324008679782084292' + '2446494189019075159822930571858728009485237489829138626896756141' + '8738958337632249177044975686477011571044266' ).neg().toString(), '-433593290010590489671135819286259593426549306666324008679782084292244' + '64941890190751598229305718587280094852374898291386268967561418738958' + '337632249177044975686477011571044266' ) t.deepEqual( BigNum( '-43359329001059048967113581928625959342654930666632400867978208429' + '2244649418901907515982293057185872800948523748982913862689675614' + '18738958337632249177044975686477011571044266' ).neg().toString(), '4335932900105904896711358192862595934265493066663240086797820842922446' + '49418901907515982293057185872800948523748982913862689675614187389583' + '37632249177044975686477011571044266' ) t.end() }) test('mod', { timeout: 120000 }, function (t) { for (var i = 0; i < 10; i++) { for (var j = 0; j < 10; j++) { var js = j.toString() if (!isNaN(i % j)) { var ks = (i % j).toString() t.deepEqual(BigNum(i).mod(j).toString(), ks) t.deepEqual(BigNum(i).mod(js).toString(), ks) t.deepEqual(BigNum(i).mod(BigNum(j)).toString(), ks) t.deepEqual(BigNum.mod(i, j).toString(), ks) } } } t.deepEqual( BigNum('486541542410442549118519277483401413') .mod('1802185856709793916115771381388554') .toString() , '1753546955507985683376775889880387' ) t.end() }) test('cmp', { timeout: 120000 }, function (t) { for (var i = -10; i <= 10; i++) { var bi = BigNum(i) for (var j = -10; j <= 10; j++) { [j, BigNum(j)].forEach(function (jj) { t.deepEqual(bi.lt(jj), i < j) t.deepEqual(bi.le(jj), i <= j) t.deepEqual(bi.eq(jj), i === j) t.deepEqual(bi.ne(jj), i !== j) t.deepEqual(bi.gt(jj), i > j) t.deepEqual(bi.ge(jj), i >= j) }) } } t.end() }) test('powm', { timeout: 120000 }, function (t) { var twos = [2, '2', BigNum(2), BigNum('2')] var tens = [100000, '100000', BigNum(100000), BigNum(100000)] twos.forEach(function (two) { tens.forEach(function (ten) { t.deepEqual( BigNum('111111111').powm(two, ten).toString(), '54321' ) }) }) t.deepEqual( BigNum('624387628734576238746587435') .powm(2732, '457676874367586') .toString() , '335581885073251' ) t.end() }) test('pow', { timeout: 120000 }, function (t) { [2, '2', BigNum(2), BigNum('2')].forEach(function (two) { t.deepEqual( BigNum('111111111').pow(two).toString(), '12345678987654321' ) }) t.deepEqual( BigNum('3487438743234789234879').pow(22).toString(), '861281136448465709000943928980299119292959327175552412961995332536782980636409994680542395362634321718164701236369695670918217801815161694902810780084448291245512671429670376051205638247649202527956041058237646154753587769450973231275642223337064356190945030999709422512682440247294915605076918925272414789710234097768366414400280590151549041536921814066973515842848197905763447515344747881160891303219471850554054186959791307149715821010152303317328860351766337716947079041' ) t.end() }) test('and', { timeout: 120000 }, function (t) { for (var i = 0; i < 256; i += 7) { for (var j = 0; j < 256; j += 7) { var js = j.toString() var ks = (i & j).toString() t.deepEqual(BigNum(i).and(j).toString(), ks) t.deepEqual(BigNum(i).and(js).toString(), ks) t.deepEqual(BigNum(i).and(BigNum(j)).toString(), ks) t.deepEqual(BigNum.and(i, j).toString(), ks) t.deepEqual(BigNum(-1 * i).and(j).toString(), ((-1 * i) & j).toString()) t.deepEqual(BigNum(i).and(-1 * j).toString(), (i & (-1 * j)).toString()) t.deepEqual(BigNum(-1 * i).and(-1 * j).toString(), ((-1 * i) & (-1 * j)).toString()) } } t.deepEqual(BigNum.and(BigNum('111111', 16), BigNum('111111', 16)).toString(16), '111111') t.deepEqual(BigNum.and(BigNum('111110', 16), BigNum('111111', 16)).toString(16), '111110') t.deepEqual(BigNum.and(BigNum('111112', 16), BigNum('111111', 16)).toString(16), '111110') t.deepEqual(BigNum.and(BigNum('111121', 16), BigNum('111111', 16)).toString(16), '111101') t.deepEqual(BigNum.and(BigNum('111131', 16), BigNum('111111', 16)).toString(16), '111111') t.deepEqual(BigNum.and(BigNum('-111111', 16), BigNum('111111', 16)).toString(16), '01') t.deepEqual(BigNum.and(BigNum('111111', 16), BigNum('-111111', 16)).toString(16), '01') t.deepEqual(BigNum.and(BigNum('-111111', 16), BigNum('-111111', 16)).toString(16), '-111111') t.end() }) test('or', { timeout: 120000 }, function (t) { for (var i = 0; i < 256; i += 7) { for (var j = 0; j < 256; j += 7) { var js = j.toString() var ks = (i | j).toString() t.deepEqual(BigNum(i).or(j).toString(), ks) t.deepEqual(BigNum(i).or(js).toString(), ks) t.deepEqual(BigNum(i).or(BigNum(j)).toString(), ks) t.deepEqual(BigNum.or(i, j).toString(), ks) t.deepEqual(BigNum(-1 * i).or(j).toString(), ((-1 * i) | j).toString()) t.deepEqual(BigNum(i).or(-1 * j).toString(), (i | (-1 * j)).toString()) t.deepEqual(BigNum(-1 * i).or(-1 * j).toString(), ((-1 * i) | (-1 * j)).toString()) } } t.deepEqual(BigNum.or(BigNum('111111', 16), BigNum('111111', 16)).toString(16), '111111') t.deepEqual(BigNum.or(BigNum('111110', 16), BigNum('111111', 16)).toString(16), '111111') t.deepEqual(BigNum.or(BigNum('111112', 16), BigNum('111111', 16)).toString(16), '111113') t.deepEqual(BigNum.or(BigNum('111121', 16), BigNum('111111', 16)).toString(16), '111131') t.deepEqual(BigNum.or(BigNum('-111111', 16), BigNum('111111', 16)).toString(16), '-01') t.deepEqual(BigNum.or(BigNum('111111', 16), BigNum('-111111', 16)).toString(16), '-01') t.deepEqual(BigNum.or(BigNum('-111111', 16), BigNum('-111111', 16)).toString(16), '-111111') t.end() }) test('xor', { timeout: 120000 }, function (t) { for (var i = 0; i < 256; i += 7) { for (var j = 0; j < 256; j += 7) { var js = j.toString() var ks = (i ^ j).toString() t.deepEqual(BigNum(i).xor(j).toString(), ks) t.deepEqual(BigNum(i).xor(js).toString(), ks) t.deepEqual(BigNum(i).xor(BigNum(j)).toString(), ks) t.deepEqual(BigNum.xor(i, j).toString(), ks) t.deepEqual(BigNum(-1 * i).xor(j).toString(), ((-1 * i) ^ j).toString()) t.deepEqual(BigNum(i).xor(-1 * j).toString(), (i ^ (-1 * j)).toString()) t.deepEqual(BigNum(-1 * i).xor(-1 * j).toString(), ((-1 * i) ^ (-1 * j)).toString()) } } t.deepEqual(BigNum.xor(BigNum('111111', 16), BigNum('111111', 16)).toString(), 0) t.deepEqual(BigNum.xor(BigNum('111110', 16), BigNum('111111', 16)).toString(), 1) t.deepEqual(BigNum.xor(BigNum('111112', 16), BigNum('111111', 16)).toString(), 3) t.deepEqual(BigNum.xor(BigNum('111121', 16), BigNum('111111', 16)).toString(), 0x30) t.deepEqual(BigNum.xor(BigNum('-111111', 16), BigNum('111111', 16)).toString(), -2) t.deepEqual(BigNum.xor(BigNum('111111', 16), BigNum('-111111', 16)).toString(), -2) t.deepEqual(BigNum.xor(BigNum('-111111', 16), BigNum('-111111', 16)).toString(), 0) t.end() }) test('rand', { timeout: 120000 }, function (t) { for (var i = 1; i < 1000; i++) { var x = BigNum(i).rand().toNumber() t.ok(x >= 0 && x < i) var y = BigNum(i).rand(i + 10).toNumber() t.ok(i <= y && y < i + 10) var z = BigNum.rand(i, i + 10).toNumber() t.ok(i <= z && z < i + 10) } t.end() }) test('primes', { timeout: 120000 }, function (t) { var ps = { 2: true, 3: true, 5: true, 7: true } for (var i = 0; i <= 10; i++) { t.deepEqual(BigNum(i).probPrime(), Boolean(ps[i])) } var ns = { 2: 3, 3: 5, 15313: 15319, 222919: 222931, 611939: 611951, 334214459: '334214467', 961748927: '961748941', 9987704933: '9987704953' } Object.keys(ns).forEach(function (n) { t.deepEqual( BigNum(n).nextPrime().toString(), ns[n].toString() ) }) var uniques = [ '3', '11', '37', '101', '9091', '9901', '333667', '909091', '99990001', '999999000001', '9999999900000001', '909090909090909091', '1111111111111111111', '11111111111111111111111', '900900900900990990990991' ] var wagstaff = [ '3', '11', '43', '683', '2731', '43691', '174763', '2796203', '715827883', '2932031007403', '768614336404564651', '201487636602438195784363', '845100400152152934331135470251', '56713727820156410577229101238628035243' ] var big = [ '4669523849932130508876392554713407521319117239637943224980015676156491', '54875133386847519273109693154204970395475080920935355580245252923343305939004903', '204005728266090048777253207241416669051476369216501266754813821619984472224780876488344279', '2074722246773485207821695222107608587480996474721117292752992589912196684750549658310084416732550077', '5628290459057877291809182450381238927697314822133923421169378062922140081498734424133112032854812293' ] ;[uniques, wagstaff, big].forEach(function (xs) { xs.forEach(function (x) { var p = BigNum(x).probPrime() t.ok(p === true || p === 'maybe') }) }) t.end() }) test('isbitset', { timeout: 120000 }, function (t) { function mkbin (bn) { var bin = '' for (var i = 0; i < bn.bitLength(); ++i) { bin += bn.isBitSet(i) ? '1' : '0' } return bin } t.deepEqual(mkbin(BigNum(127)), '1111111') t.deepEqual(mkbin(BigNum(-127)), '1111111') t.deepEqual(mkbin(BigNum(128)), '00000001') t.deepEqual(mkbin(BigNum(-128)), '00000001') t.deepEqual(mkbin(BigNum(129)), '10000001') t.deepEqual(mkbin(BigNum(-129)), '10000001') t.end() }) test('invertm', { timeout: 120000 }, function (t) { // numbers from http://www.itl.nist.gov/fipspubs/fip186.htm appendix 5 var q = BigNum('b20db0b101df0c6624fc1392ba55f77d577481e5', 16) var k = BigNum('79577ddcaafddc038b865b19f8eb1ada8a2838c6', 16) var kinv = k.invertm(q) t.deepEqual(kinv.toString(16), '2784e3d672d972a74e22c67f4f4f726ecc751efa') t.end() }) test('shift', { timeout: 120000 }, function (t) { t.deepEqual(BigNum(37).shiftLeft(2).toString(), (37 << 2).toString()) // 148 t.deepEqual(BigNum(37).shiftRight(2).toString(), (37 >> 2).toString()) // 9 t.equal( BigNum(2).pow(Math.pow(2, 10)).shiftRight(4).toString(), BigNum(2).pow(Math.pow(2, 10)).div(16).toString() ) t.end() }) test('mod', { timeout: 120000 }, function (t) { t.deepEqual(BigNum(55555).mod(2).toString(), '1') t.deepEqual( BigNum('1234567').mod( BigNum('4321') ).toNumber(), 1234567 % 4321 ) t.end() }) test('endian', { timeout: 120000 }, function (t) { var a = BigNum(0x0102030405) t.deepEqual(a.toBuffer({ endian: 'big', size: 2 }).toString('hex'), '000102030405') t.deepEqual(a.toBuffer({ endian: 'little', size: 2 }).toString('hex'), '010003020504') var b = BigNum(0x0102030405) t.deepEqual(b.toBuffer({ endian: 'big', size: 'auto' }).toString('hex'), '0102030405') t.deepEqual(b.toBuffer({ endian: 'little', size: 'auto' }).toString('hex'), '0504030201') var c = Buffer.from('000102030405', 'hex') t.deepEqual(BigNum.fromBuffer(c, { endian: 'big', size: 'auto' }).toString(16), '0102030405') t.deepEqual(BigNum.fromBuffer(c, { endian: 'little', size: 'auto' }).toString(16), '050403020100') t.end() }) test('bitlength', { timeout: 120000 }, function (t) { var bl = BigNum( '433593290010590489671135819286259593426549306666324008679782084292' + '2446494189019075159822930571858728009485237489829138626896756141' + '873895833763224917704497568647701157104426' ).bitLength() t.equal(bl > 0, true) t.end() }) test('gcd', { timeout: 120000 }, function (t) { var b1 = BigNum('234897235923342343242') var b2 = BigNum('234790237101762305340234') var expected = BigNum('6') t.equal(b1.gcd(b2).toString(), expected.toString()) t.end() }) test('jacobi', { timeout: 120000 }, function (t) { // test case from p. 134 of D. R. Stinson var b1 = BigNum('7411') var b2 = BigNum('9283') t.equal(b1.jacobi(b2), -1) // test case from p. 132 of D. R. Stinson b1 = BigNum('6278') b2 = BigNum('9975') t.equal(b1.jacobi(b2), -1) // test case from p. 74 of Men. Oorsh. Vans. b1 = BigNum('158') b2 = BigNum('235') t.equal(b1.jacobi(b2), -1) // test case from p. 216 of Kumanduri Romero b1 = BigNum('4') b2 = BigNum('7') t.equal(b1.jacobi(b2), 1) // test case from p. 363 of K. R. Rosen b1 = BigNum('68') b2 = BigNum('111') t.equal(b1.jacobi(b2), 1) t.end() }) ================================================ FILE: test/buf.js ================================================ var BigNum = require('../') var put = require('put') var test = require('tap').test var Buffer = require('safe-buffer').Buffer test('bufBe', function (t) { var buf1 = Buffer.from([1, 2, 3, 4]) var num = BigNum.fromBuffer(buf1, { size: 4 }).toNumber() t.deepEqual( num, 1 * Math.pow(256, 3) + 2 * Math.pow(256, 2) + 3 * 256 + 4 ) var buf2 = put().word32be(num).buffer() t.deepEqual(buf1, buf2, '[ ' + [].slice.call(buf1) + ' ] != [ ' + [].slice.call(buf2) + ' ]' ) t.end() }) test('bufLe', function (t) { var buf1 = Buffer.from([1, 2, 3, 4]) var num = BigNum .fromBuffer(buf1, { size: 4, endian: 'little' }) .toNumber() var buf2 = put().word32le(num).buffer() t.deepEqual(buf1, buf2, '[ ' + [].join.call(buf1, ',') + ' ] != [ ' + [].join.call(buf2, ',') + ' ]' ) t.end() }) test('bufBe_le', function (t) { var bufBe = Buffer.from([1, 2, 3, 4, 5, 6, 7, 8]) var bufLe = Buffer.from([4, 3, 2, 1, 8, 7, 6, 5]) var numBe = BigNum .fromBuffer(bufBe, { size: 4, endian: 'big' }) .toString() var numLe = BigNum .fromBuffer(bufLe, { size: 4, endian: 'little' }) .toString() t.deepEqual(numBe, numLe) t.end() }) test('buf_high_bits', function (t) { var bufBe = Buffer.from([ 201, 202, 203, 204, 205, 206, 207, 208 ]) var bufLe = Buffer.from([ 204, 203, 202, 201, 208, 207, 206, 205 ]) var numBe = BigNum .fromBuffer(bufBe, { size: 4, endian: 'big' }) .toString() var numLe = BigNum .fromBuffer(bufLe, { size: 4, endian: 'little' }) .toString() t.deepEqual(numBe, numLe) t.end() }) test('buf_to_from', function (t) { var nums = [ 0, 1, 10, 15, 3, 16, 7238, 1337, 31337, 505050, '172389721984375328763297498273498732984324', '32848432742', '12988282841231897498217398217398127983721983719283721', '718293798217398217312387213972198321' ] nums.forEach(function (num) { var b = BigNum(num) var u = b.toBuffer() t.ok(u) t.deepEqual( BigNum.fromBuffer(u).toString(), b.toString() ) }) t.throws(function () { BigNum(-1).toBuffer() // can't pack negative numbers yet }) t.end() }) test('toBuf', function (t) { var buf = Buffer.from([0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f]) var b = BigNum( 0x0a * 256 * 256 * 256 * 256 * 256 + 0x0b * 256 * 256 * 256 * 256 + 0x0c * 256 * 256 * 256 + 0x0d * 256 * 256 + 0x0e * 256 + 0x0f ) t.deepEqual(b.toString(16), '0a0b0c0d0e0f') t.deepEqual( [].slice.call(b.toBuffer({ endian: 'big', size: 2 })), [0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f] ) t.deepEqual( [].slice.call(b.toBuffer({ endian: 'little', size: 2 })), [0x0b, 0x0a, 0x0d, 0x0c, 0x0f, 0x0e] ) t.deepEqual( BigNum.fromBuffer(buf).toString(16), b.toString(16) ) t.deepEqual( [].slice.call(BigNum(43135012110).toBuffer({ endian: 'little', size: 4 })), [0x0a, 0x00, 0x00, 0x00, 0x0e, 0x0d, 0x0c, 0x0b] ) t.deepEqual( [].slice.call(BigNum(43135012110).toBuffer({ endian: 'big', size: 4 })), [0x00, 0x00, 0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e] ) t.end() }) test('zeroPad', function (t) { var b = BigNum(0x123456) t.deepEqual( [].slice.call(b.toBuffer({ endian: 'big', size: 4 })), [0x00, 0x12, 0x34, 0x56] ) t.deepEqual( [].slice.call(b.toBuffer({ endian: 'little', size: 4 })), [0x56, 0x34, 0x12, 0x00] ) t.end() }) test('toMpint', function (t) { // test values taken directly out of // http://tools.ietf.org/html/rfc4251#page-10 var refs = { 0: Buffer.from([0x00, 0x00, 0x00, 0x00]), '9a378f9b2e332a7': Buffer.from([ 0x00, 0x00, 0x00, 0x08, 0x09, 0xa3, 0x78, 0xf9, 0xb2, 0xe3, 0x32, 0xa7 ]), 80: Buffer.from([0x00, 0x00, 0x00, 0x02, 0x00, 0x80]), '-1234': Buffer.from([0x00, 0x00, 0x00, 0x02, 0xed, 0xcc]), '-deadbeef': Buffer.from([0x00, 0x00, 0x00, 0x05, 0xff, 0x21, 0x52, 0x41, 0x11]) } Object.keys(refs).forEach(function (key) { var buf0 = BigNum(key, 16).toBuffer('mpint') var buf1 = refs[key] t.deepEqual( buf0, buf1, buf0.inspect() + ' != ' + buf1.inspect() + ' for BigNum(' + key + ')' ) }) t.end() }) ================================================ FILE: test/gh52.js ================================================ var BigNum = require('../') var test = require('tap').test test('github52', function (t) { // verify that numbers aren't truncated to 32 bits when running on // 32-bit platforms (where the OpenSSL sizeof(BN_ULONG) is 32 bits) var num = new BigNum(0x100000000) t.equal(num.toString(), '4294967296') t.equal(num.add(0x100000000).toString(), '8589934592') t.equal(num.sub(0x100000001).toString(), '-1') t.equal(num.mul(0x100000000).toString().toString(), '18446744073709551616') t.equal(num.div(0x100000002).toString(), '0') t.equal(num.mod(0x100000002).toString(), '4294967296') num = new BigNum(2) t.equal(num.powm(0x100000001, 4).toString(), '0') num = new BigNum(-0x100000000) t.ok(num.cmp(-0x100000000) === 0) num = new BigNum(0x100000000) t.ok(num.cmp(0x100000000) === 0) t.end() }) ================================================ FILE: test/isbignum.js ================================================ var BigNum = require('../') var test = require('tap').test test('create', function (t) { var validBn = BigNum('42') var testObj testObj = BigNum('123') t.equal(BigNum.isBigNum(testObj), true) testObj = {} t.equal(BigNum.isBigNum(testObj), false) testObj = {} t.throws(function () { validBn.add(testObj) }) testObj = falsePositive() t.equal(BigNum.isBigNum(testObj), true) // this causes a hard crash, so its disabled for now // testObj = falsePositive() // t.throws(function() { // validBn.add(testObj) // }) t.end() }) function falsePositive () { var obj = {} for (var key in BigNum.prototype) { obj[key] = true } return obj } ================================================ FILE: test/seed.js ================================================ // skip on Windows for now, this doesn't work if (process.platform === 'win32') { process.exit(0) } var path = require('path') var execFile = require('child_process').execFile var test = require('tap').test test('rand', function (t) { var to = setTimeout(function () { t.fail('never executed') }, 5000) var args = [ '-p', 'require("' + path.join(__dirname, '..') + '").rand(1000).toString()' ] execFile(process.execPath, args, function (err1, r1) { execFile(process.execPath, args, function (err2, r2) { clearTimeout(to) t.ifError(err1) t.ifError(err2) t.ok( r1.match(/^\d+[\r\n]+/), JSON.stringify(r1) + ' is not an integer' ) t.ok( r2.match(/^\d+[\r\n]+/), JSON.stringify(r2) + ' is not an integer' ) var n1 = parseInt(r1.split(/[\r\n]+/)[0], 10) var n2 = parseInt(r2.split(/[\r\n]+/)[0], 10) t.ok(n1 >= 0, 'n1 >= 0') t.ok(n2 >= 0, 'n2 >= 0') t.ok(n1 < 1000, 'n1 < 1000') t.ok(n2 < 1000, 'n2 < 1000') t.ok(n1 !== n2, 'n1 != n2') t.end() }) }) }) ================================================ FILE: test/wincrash.js ================================================ var BigNum = require('../') var test = require('tap').test test('windowsCrash', function (t) { var num = new BigNum(1234) t.equal(num.toString(), '1234') t.end() })