#include #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 (args.Length()<= (I) || !args[I]->IsString()) \ return ThrowException(Exception::TypeError( \ String::New("Argument " #I " must be a string"))); \ Local VAR = Local::Cast(args[I]); #define REQ_UTF8_ARG(I, VAR) \ if (args.Length() <= (I) || !args[I]->IsString()) \ return ThrowException(Exception::TypeError( \ String::New("Argument " #I " must be a utf8 string"))); \ String::Utf8Value VAR(args[I]->ToString()); #define REQ_INT32_ARG(I, VAR) \ if (args.Length() <= (I) || !args[I]->IsInt32()) \ return ThrowException(Exception::TypeError( \ String::New("Argument " #I " must be an int32"))); \ int32_t VAR = args[I]->ToInt32()->Value(); #define REQ_UINT32_ARG(I, VAR) \ if (args.Length() <= (I) || !args[I]->IsUint32()) \ return ThrowException(Exception::TypeError( \ String::New("Argument " #I " must be a uint32"))); \ uint32_t VAR = args[I]->ToUint32()->Value(); #define REQ_INT64_ARG(I, VAR) \ if (args.Length() <= (I) || !args[I]->IsNumber()) \ return ThrowException(Exception::TypeError( \ String::New("Argument " #I " must be an int64"))); \ int64_t VAR = args[I]->ToInteger()->Value(); #define REQ_UINT64_ARG(I, VAR) \ if (args.Length() <= (I) || !args[I]->IsNumber()) \ return ThrowException(Exception::TypeError( \ String::New("Argument " #I " must be a uint64"))); \ uint64_t VAR = args[I]->ToInteger()->Value(); #define REQ_BOOL_ARG(I, VAR) \ if (args.Length() <= (I) || !args[I]->IsBoolean()) \ return ThrowException(Exception::TypeError( \ String::New("Argument " #I " must be a boolean"))); \ bool VAR = args[I]->ToBoolean()->Value(); #define WRAP_RESULT(RES, VAR) \ Handle arg[1] = { External::New(static_cast(RES)) }; \ Local VAR = constructor_template->GetFunction()->NewInstance(1, arg); 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 : ObjectWrap { public: static void Initialize(Handle target); BIGNUM bignum_; static Persistent js_conditioner; static void SetJSConditioner(Persistent constructor); protected: static Persistent constructor_template; BigNum(const String::Utf8Value& str, uint64_t base); BigNum(uint64_t num); BigNum(int64_t num); BigNum(BIGNUM *num); BigNum(); ~BigNum(); static Handle New(const Arguments& args); static Handle ToString(const Arguments& args); static Handle Badd(const Arguments& args); static Handle Bsub(const Arguments& args); static Handle Bmul(const Arguments& args); static Handle Bdiv(const Arguments& args); static Handle Uadd(const Arguments& args); static Handle Usub(const Arguments& args); static Handle Umul(const Arguments& args); static Handle Udiv(const Arguments& args); static Handle Umul_2exp(const Arguments& args); static Handle Udiv_2exp(const Arguments& args); static Handle Babs(const Arguments& args); static Handle Bneg(const Arguments& args); static Handle Bmod(const Arguments& args); static Handle Umod(const Arguments& args); static Handle Bpowm(const Arguments& args); static Handle Upowm(const Arguments& args); static Handle Upow(const Arguments& args); static Handle Uupow(const Arguments& args); static Handle Brand0(const Arguments& args); static Handle Uprime0(const Arguments& args); static Handle Probprime(const Arguments& args); static Handle Bcompare(const Arguments& args); static Handle Scompare(const Arguments& args); static Handle Ucompare(const Arguments& args); static Handle Bop(const Arguments& args, int op); static Handle Band(const Arguments& args); static Handle Bor(const Arguments& args); static Handle Bxor(const Arguments& args); static Handle Binvertm(const Arguments& args); static Handle Bsqrt(const Arguments& args); static Handle Broot(const Arguments& args); static Handle BitLength(const Arguments& args); static Handle Bgcd(const Arguments& args); static Handle Bjacobi(const Arguments& args); }; Persistent BigNum::constructor_template; Persistent BigNum::js_conditioner; void BigNum::SetJSConditioner(Persistent constructor) { js_conditioner = constructor; } void BigNum::Initialize(v8::Handle target) { HandleScope scope; Local t = FunctionTemplate::New(New); constructor_template = Persistent::New(t); constructor_template->InstanceTemplate()->SetInternalFieldCount(1); constructor_template->SetClassName(String::NewSymbol("BigNum")); NODE_SET_METHOD(constructor_template, "uprime0", Uprime0); NODE_SET_PROTOTYPE_METHOD(constructor_template, "tostring", ToString); NODE_SET_PROTOTYPE_METHOD(constructor_template, "badd", Badd); NODE_SET_PROTOTYPE_METHOD(constructor_template, "bsub", Bsub); NODE_SET_PROTOTYPE_METHOD(constructor_template, "bmul", Bmul); NODE_SET_PROTOTYPE_METHOD(constructor_template, "bdiv", Bdiv); NODE_SET_PROTOTYPE_METHOD(constructor_template, "uadd", Uadd); NODE_SET_PROTOTYPE_METHOD(constructor_template, "usub", Usub); NODE_SET_PROTOTYPE_METHOD(constructor_template, "umul", Umul); NODE_SET_PROTOTYPE_METHOD(constructor_template, "udiv", Udiv); NODE_SET_PROTOTYPE_METHOD(constructor_template, "umul2exp", Umul_2exp); NODE_SET_PROTOTYPE_METHOD(constructor_template, "udiv2exp", Udiv_2exp); NODE_SET_PROTOTYPE_METHOD(constructor_template, "babs", Babs); NODE_SET_PROTOTYPE_METHOD(constructor_template, "bneg", Bneg); NODE_SET_PROTOTYPE_METHOD(constructor_template, "bmod", Bmod); NODE_SET_PROTOTYPE_METHOD(constructor_template, "umod", Umod); NODE_SET_PROTOTYPE_METHOD(constructor_template, "bpowm", Bpowm); NODE_SET_PROTOTYPE_METHOD(constructor_template, "upowm", Upowm); NODE_SET_PROTOTYPE_METHOD(constructor_template, "upow", Upow); NODE_SET_PROTOTYPE_METHOD(constructor_template, "brand0", Brand0); NODE_SET_PROTOTYPE_METHOD(constructor_template, "probprime", Probprime); NODE_SET_PROTOTYPE_METHOD(constructor_template, "bcompare", Bcompare); NODE_SET_PROTOTYPE_METHOD(constructor_template, "scompare", Scompare); NODE_SET_PROTOTYPE_METHOD(constructor_template, "ucompare", Ucompare); NODE_SET_PROTOTYPE_METHOD(constructor_template, "band", Band); NODE_SET_PROTOTYPE_METHOD(constructor_template, "bor", Bor); NODE_SET_PROTOTYPE_METHOD(constructor_template, "bxor", Bxor); NODE_SET_PROTOTYPE_METHOD(constructor_template, "binvertm", Binvertm); NODE_SET_PROTOTYPE_METHOD(constructor_template, "bsqrt", Bsqrt); NODE_SET_PROTOTYPE_METHOD(constructor_template, "broot", Broot); NODE_SET_PROTOTYPE_METHOD(constructor_template, "bitLength", BitLength); NODE_SET_PROTOTYPE_METHOD(constructor_template, "gcd", Bgcd); NODE_SET_PROTOTYPE_METHOD(constructor_template, "jacobi", Bjacobi); target->Set(String::NewSymbol("BigNum"), constructor_template->GetFunction()); } BigNum::BigNum(const v8::String::Utf8Value& str, uint64_t base) : ObjectWrap () { BN_init(&bignum_); BN_zero(&bignum_); BIGNUM *res = &bignum_; const char *cstr = *str; switch (base) { case 2: BN_init(&bignum_); 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: ThrowException(Exception::Error(String::New("Invalid base, only 10 and 16 are supported"))); return; } } BigNum::BigNum(uint64_t num) : ObjectWrap () { BN_init(&bignum_); BN_set_word(&bignum_, num); } BigNum::BigNum(int64_t num) : ObjectWrap () { BN_init(&bignum_); if (num > 0) { BN_set_word(&bignum_, num); } else { BN_set_word(&bignum_, -num); BN_set_negative(&bignum_, 1); } } BigNum::BigNum(BIGNUM *num) : ObjectWrap () { BN_init(&bignum_); BN_copy(&bignum_, num); } BigNum::BigNum() : ObjectWrap () { BN_init(&bignum_); BN_zero(&bignum_); } BigNum::~BigNum() { BN_clear_free(&bignum_); } Handle BigNum::New(const Arguments& args) { if (!args.IsConstructCall()) { int len = args.Length(); Handle* newArgs = new Handle[len]; for (int i = 0; i < len; i++) { newArgs[i] = args[i]; } Handle newInst = constructor_template->GetFunction()->NewInstance(len, newArgs); delete[] newArgs; return newInst; } HandleScope scope; BigNum *bignum; uint64_t base; if (args[0]->IsExternal()) { bignum = static_cast(External::Cast(*(args[0]))->Value()); } else { int len = args.Length(); Local ctx = Local::New(Object::New()); Handle* newArgs = new Handle[len]; for (int i = 0; i < len; i++) { newArgs[i] = args[i]; } Local obj = js_conditioner->Call(ctx, args.Length(), newArgs); delete[] newArgs; if (!*obj) { return ThrowException(Exception::Error(String::New("Invalid type passed to bignum constructor"))); } String::Utf8Value str(obj->ToObject()->Get(String::NewSymbol("num"))->ToString()); base = obj->ToObject()->Get(String::NewSymbol("base"))->ToNumber()->Value(); bignum = new BigNum(str, base); } bignum->Wrap(args.This()); return scope.Close(args.This()); } Handle BigNum::ToString(const Arguments& args) { BigNum *bignum = ObjectWrap::Unwrap(args.This()); HandleScope scope; uint64_t base = 10; if (args.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: return ThrowException(Exception::Error(String::New("Invalid base, only 10 and 16 are supported"))); } Handle result = String::New(to); free(to); return scope.Close(result); } Handle BigNum::Badd(const Arguments& args) { BigNum *bignum = ObjectWrap::Unwrap(args.This()); HandleScope scope; BigNum *bn = ObjectWrap::Unwrap(args[0]->ToObject()); BigNum *res = new BigNum(); BN_add(&res->bignum_, &bignum->bignum_, &bn->bignum_); WRAP_RESULT(res, result); return scope.Close(result); } Handle BigNum::Bsub(const Arguments& args) { BigNum *bignum = ObjectWrap::Unwrap(args.This()); HandleScope scope; BigNum *bn = ObjectWrap::Unwrap(args[0]->ToObject()); BigNum *res = new BigNum(); BN_sub(&res->bignum_, &bignum->bignum_, &bn->bignum_); WRAP_RESULT(res, result); return scope.Close(result); } Handle BigNum::Bmul(const Arguments& args) { AutoBN_CTX ctx; BigNum *bignum = ObjectWrap::Unwrap(args.This()); HandleScope scope; BigNum *bn = ObjectWrap::Unwrap(args[0]->ToObject()); BigNum *res = new BigNum(); BN_mul(&res->bignum_, &bignum->bignum_, &bn->bignum_, ctx); WRAP_RESULT(res, result); return scope.Close(result); } Handle BigNum::Bdiv(const Arguments& args) { AutoBN_CTX ctx; BigNum *bignum = ObjectWrap::Unwrap(args.This()); HandleScope scope; BigNum *bi = ObjectWrap::Unwrap(args[0]->ToObject()); BigNum *res = new BigNum(); BN_div(&res->bignum_, NULL, &bignum->bignum_, &bi->bignum_, ctx); WRAP_RESULT(res, result); return scope.Close(result); } Handle BigNum::Uadd(const Arguments& args) { BigNum *bignum = ObjectWrap::Unwrap(args.This()); HandleScope scope; REQ_UINT64_ARG(0, x); BigNum *res = new BigNum(&bignum->bignum_); BN_add_word(&res->bignum_, x); WRAP_RESULT(res, result); return scope.Close(result); } Handle BigNum::Usub(const Arguments& args) { BigNum *bignum = ObjectWrap::Unwrap(args.This()); HandleScope scope; REQ_UINT64_ARG(0, x); BigNum *res = new BigNum(&bignum->bignum_); BN_sub_word(&res->bignum_, x); WRAP_RESULT(res, result); return scope.Close(result); } Handle BigNum::Umul(const Arguments& args) { BigNum *bignum = ObjectWrap::Unwrap(args.This()); HandleScope scope; REQ_UINT64_ARG(0, x); BigNum *res = new BigNum(&bignum->bignum_); BN_mul_word(&res->bignum_, x); WRAP_RESULT(res, result); return scope.Close(result); } Handle BigNum::Udiv(const Arguments& args) { BigNum *bignum = ObjectWrap::Unwrap(args.This()); HandleScope scope; REQ_UINT64_ARG(0, x); BigNum *res = new BigNum(&bignum->bignum_); BN_div_word(&res->bignum_, x); WRAP_RESULT(res, result); return scope.Close(result); } Handle BigNum::Umul_2exp(const Arguments& args) { BigNum *bignum = ObjectWrap::Unwrap(args.This()); HandleScope scope; REQ_UINT64_ARG(0, x); BigNum *res = new BigNum(); BN_lshift(&res->bignum_, &bignum->bignum_, x); WRAP_RESULT(res, result); return scope.Close(result); } Handle BigNum::Udiv_2exp(const Arguments& args) { BigNum *bignum = ObjectWrap::Unwrap(args.This()); HandleScope scope; REQ_UINT64_ARG(0, x); BigNum *res = new BigNum(); BN_rshift(&res->bignum_, &bignum->bignum_, x); WRAP_RESULT(res, result); return scope.Close(result); } Handle BigNum::Babs(const Arguments& args) { BigNum *bignum = ObjectWrap::Unwrap(args.This()); HandleScope scope; BigNum *res = new BigNum(&bignum->bignum_); BN_set_negative(&res->bignum_, 0); WRAP_RESULT(res, result); return scope.Close(result); } Handle BigNum::Bneg(const Arguments& args) { BigNum *bignum = ObjectWrap::Unwrap(args.This()); HandleScope scope; BigNum *res = new BigNum(&bignum->bignum_); BN_set_negative(&res->bignum_, !BN_is_negative(&res->bignum_)); WRAP_RESULT(res, result); return scope.Close(result); } Handle BigNum::Bmod(const Arguments& args) { AutoBN_CTX ctx; BigNum *bignum = ObjectWrap::Unwrap(args.This()); HandleScope scope; BigNum *bn = ObjectWrap::Unwrap(args[0]->ToObject()); BigNum *res = new BigNum(); BN_div(NULL, &res->bignum_, &bignum->bignum_, &bn->bignum_, ctx); WRAP_RESULT(res, result); return scope.Close(result); } Handle BigNum::Umod(const Arguments& args) { BigNum *bignum = ObjectWrap::Unwrap(args.This()); HandleScope scope; REQ_UINT64_ARG(0, x); BigNum *res = new BigNum(); BN_set_word(&res->bignum_, BN_mod_word(&bignum->bignum_, x)); WRAP_RESULT(res, result); return scope.Close(result); } Handle BigNum::Bpowm(const Arguments& args) { AutoBN_CTX ctx; BigNum *bignum = ObjectWrap::Unwrap(args.This()); HandleScope scope; BigNum *bn1 = ObjectWrap::Unwrap(args[0]->ToObject()); BigNum *bn2 = ObjectWrap::Unwrap(args[1]->ToObject()); BigNum *res = new BigNum(); BN_mod_exp(&res->bignum_, &bignum->bignum_, &bn1->bignum_, &bn2->bignum_, ctx); WRAP_RESULT(res, result); return scope.Close(result); } Handle BigNum::Upowm(const Arguments& args) { AutoBN_CTX ctx; BigNum *bignum = ObjectWrap::Unwrap(args.This()); HandleScope scope; REQ_UINT64_ARG(0, x); BigNum *bn = ObjectWrap::Unwrap(args[1]->ToObject()); BIGNUM exp; BN_init(&exp); BN_set_word(&exp, x); BigNum *res = new BigNum(); BN_mod_exp(&res->bignum_, &bignum->bignum_, &exp, &bn->bignum_, ctx); BN_clear_free(&exp); WRAP_RESULT(res, result); return scope.Close(result); } Handle BigNum::Upow(const Arguments& args) { AutoBN_CTX ctx; BigNum *bignum = ObjectWrap::Unwrap(args.This()); HandleScope scope; REQ_UINT64_ARG(0, x); BIGNUM exp; BN_init(&exp); BN_set_word(&exp, x); BigNum *res = new BigNum(); BN_exp(&res->bignum_, &bignum->bignum_, &exp, ctx); BN_clear_free(&exp); WRAP_RESULT(res, result); return scope.Close(result); } Handle BigNum::Brand0(const Arguments& args) { BigNum *bignum = ObjectWrap::Unwrap(args.This()); HandleScope scope; BigNum *res = new BigNum(); BN_rand_range(&res->bignum_, &bignum->bignum_); WRAP_RESULT(res, result); return scope.Close(result); } Handle BigNum::Uprime0(const Arguments& args) { HandleScope scope; 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); return scope.Close(result); } Handle BigNum::Probprime(const Arguments& args) { AutoBN_CTX ctx; BigNum *bignum = ObjectWrap::Unwrap(args.This()); HandleScope scope; REQ_UINT32_ARG(0, reps); return scope.Close(Number::New(BN_is_prime_ex(&bignum->bignum_, reps, ctx, NULL))); } Handle BigNum::Bcompare(const Arguments& args) { BigNum *bignum = ObjectWrap::Unwrap(args.This()); HandleScope scope; BigNum *bn = ObjectWrap::Unwrap(args[0]->ToObject()); return scope.Close(Number::New(BN_cmp(&bignum->bignum_, &bn->bignum_))); } Handle BigNum::Scompare(const Arguments& args) { BigNum *bignum = ObjectWrap::Unwrap(args.This()); HandleScope scope; REQ_INT64_ARG(0, x); BIGNUM bn; BN_init(&bn); if (x > 0) { BN_set_word(&bn, x); } else { BN_set_word(&bn, -x); BN_set_negative(&bn, 1); } int res = BN_cmp(&bignum->bignum_, &bn); BN_clear_free(&bn); return scope.Close(Number::New(res)); } Handle BigNum::Ucompare(const Arguments& args) { BigNum *bignum = ObjectWrap::Unwrap(args.This()); HandleScope scope; REQ_UINT64_ARG(0, x); BIGNUM bn; BN_init(&bn); BN_set_word(&bn, x); int res = BN_cmp(&bignum->bignum_, &bn); BN_clear_free(&bn); return scope.Close(Number::New(res)); } Handle BigNum::Bop(const Arguments& args, int op) { BigNum *bignum = ObjectWrap::Unwrap(args.This()); BigNum *bn = ObjectWrap::Unwrap(args[0]->ToObject()); HandleScope scope; if (BN_is_negative(&bignum->bignum_) || BN_is_negative(&bn->bignum_)) { // Using BN_bn2mpi and BN_bn2mpi would make this more manageable; added in SSLeay 0.9.0 return ThrowException(Exception::Error(String::New("Bitwise operations on negative numbers are not supported"))); } 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_num_bytes(&bignum->bignum_); int maskSize = BN_num_bytes(&bn->bignum_); int 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_bn2bin(&bignum->bignum_, (unsigned char*) (payload + payloadOffset)); BN_bn2bin(&bn->bignum_, (unsigned char*) (mask + maskOffset)); 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; } BN_bin2bn((unsigned char*) payload, size, &res->bignum_); WRAP_RESULT(res, result); free(payload); free(mask); return scope.Close(result); } Handle BigNum::Band(const Arguments& args) { return Bop(args, 0); } Handle BigNum::Bor(const Arguments& args) { return Bop(args, 1); } Handle BigNum::Bxor(const Arguments& args) { return Bop(args, 2); } Handle BigNum::Binvertm(const Arguments& args) { AutoBN_CTX ctx; BigNum *bignum = ObjectWrap::Unwrap(args.This()); HandleScope scope; BigNum *bn = ObjectWrap::Unwrap(args[0]->ToObject()); BigNum *res = new BigNum(); BN_mod_inverse(&res->bignum_, &bignum->bignum_, &bn->bignum_, ctx); WRAP_RESULT(res, result); return scope.Close(result); } Handle BigNum::Bsqrt(const Arguments& args) { //BigNum *bignum = ObjectWrap::Unwrap(args.This()); HandleScope scope; return ThrowException(Exception::Error(String::New("sqrt is not supported by OpenSSL."))); } Handle BigNum::Broot(const Arguments& args) { //BigNum *bignum = ObjectWrap::Unwrap(args.This()); HandleScope scope; return ThrowException(Exception::Error(String::New("root is not supported by OpenSSL."))); } Handle BigNum::BitLength(const Arguments& args) { BigNum *bignum = ObjectWrap::Unwrap(args.This()); HandleScope scope; int size = BN_num_bits(&bignum->bignum_); Handle result = Integer::New(size); return scope.Close(result); } Handle BigNum::Bgcd(const Arguments& args) { AutoBN_CTX ctx; BigNum *bignum = ObjectWrap::Unwrap(args.This()); HandleScope scope; BigNum *bi = ObjectWrap::Unwrap(args[0]->ToObject()); BigNum *res = new BigNum(); BN_gcd(&res->bignum_, &bignum->bignum_, &bi->bignum_, ctx); WRAP_RESULT(res, result); return scope.Close(result); } Handle BigNum::Bjacobi(const Arguments& args) { AutoBN_CTX ctx; BigNum *bn_a = ObjectWrap::Unwrap(args.This()); HandleScope scope; BigNum *bn_n = ObjectWrap::Unwrap(args[0]->ToObject()); int res = 0; if (BN_jacobi_priv(&bn_a->bignum_, &bn_n->bignum_, &res, ctx) == -1) return ThrowException(Exception::Error(String::New( "Jacobi symbol calculation failed"))); return scope.Close(Integer::New(res)); } static Handle SetJSConditioner(const Arguments& args) { HandleScope scope; BigNum::SetJSConditioner(Persistent::New(Local::Cast(args[0]))); return Undefined(); } extern "C" void init (Handle target) { HandleScope scope; BigNum::Initialize(target); NODE_SET_METHOD(target, "setJSConditioner", SetJSConditioner); } NODE_MODULE(bignum, init)