2015-01-13 15:49:38 -10:00
; ( function ( ) {
2015-01-14 11:24:45 -10:00
// Note: For maximum-speed code, see "Optimizing Code" on the Emscripten wiki, https://github.com/kripken/emscripten/wiki/Optimizing-Code
// Note: Some Emscripten settings may limit the speed of the generated code.
try {
this [ 'Module' ] = Module ;
Module . test ;
} catch ( e ) {
this [ 'Module' ] = Module = { } ;
}
// The environment setup code below is customized to use Module.
// *** Environment setup code ***
var ENVIRONMENT _IS _NODE = typeof process === 'object' && typeof require === 'function' ;
var ENVIRONMENT _IS _WEB = typeof window === 'object' ;
var ENVIRONMENT _IS _WORKER = typeof importScripts === 'function' ;
var ENVIRONMENT _IS _SHELL = ! ENVIRONMENT _IS _WEB && ! ENVIRONMENT _IS _NODE && ! ENVIRONMENT _IS _WORKER ;
if ( typeof module === "object" ) {
module . exports = Module ;
}
if ( ENVIRONMENT _IS _NODE ) {
// Expose functionality in the same simple way that the shells work
// Note that we pollute the global namespace here, otherwise we break in node
Module [ 'print' ] = function ( x ) {
process [ 'stdout' ] . write ( x + '\n' ) ;
} ;
Module [ 'printErr' ] = function ( x ) {
process [ 'stderr' ] . write ( x + '\n' ) ;
} ;
var nodeFS = require ( 'fs' ) ;
var nodePath = require ( 'path' ) ;
Module [ 'read' ] = function ( filename , binary ) {
filename = nodePath [ 'normalize' ] ( filename ) ;
var ret = nodeFS [ 'readFileSync' ] ( filename ) ;
// The path is absolute if the normalized version is the same as the resolved.
if ( ! ret && filename != nodePath [ 'resolve' ] ( filename ) ) {
filename = path . join ( _ _dirname , '..' , 'src' , filename ) ;
ret = nodeFS [ 'readFileSync' ] ( filename ) ;
}
if ( ret && ! binary ) ret = ret . toString ( ) ;
return ret ;
} ;
Module [ 'readBinary' ] = function ( filename ) { return Module [ 'read' ] ( filename , true ) } ;
Module [ 'load' ] = function ( f ) {
globalEval ( read ( f ) ) ;
} ;
if ( ! Module [ 'arguments' ] ) {
Module [ 'arguments' ] = process [ 'argv' ] . slice ( 2 ) ;
}
}
if ( ENVIRONMENT _IS _SHELL ) {
Module [ 'print' ] = print ;
if ( typeof printErr != 'undefined' ) Module [ 'printErr' ] = printErr ; // not present in v8 or older sm
Module [ 'read' ] = read ;
Module [ 'readBinary' ] = function ( f ) {
return read ( f , 'binary' ) ;
} ;
if ( ! Module [ 'arguments' ] ) {
if ( typeof scriptArgs != 'undefined' ) {
Module [ 'arguments' ] = scriptArgs ;
} else if ( typeof arguments != 'undefined' ) {
Module [ 'arguments' ] = arguments ;
}
}
}
if ( ENVIRONMENT _IS _WEB && ! ENVIRONMENT _IS _WORKER ) {
if ( ! Module [ 'print' ] ) {
Module [ 'print' ] = function ( x ) {
console . log ( x ) ;
} ;
}
if ( ! Module [ 'printErr' ] ) {
Module [ 'printErr' ] = function ( x ) {
console . log ( x ) ;
} ;
}
}
if ( ENVIRONMENT _IS _WEB || ENVIRONMENT _IS _WORKER ) {
Module [ 'read' ] = function ( url ) {
var xhr = new XMLHttpRequest ( ) ;
xhr . open ( 'GET' , url , false ) ;
xhr . send ( null ) ;
return xhr . responseText ;
} ;
if ( ! Module [ 'arguments' ] ) {
if ( typeof arguments != 'undefined' ) {
Module [ 'arguments' ] = arguments ;
}
}
}
if ( ENVIRONMENT _IS _WORKER ) {
// We can do very little here...
var TRY _USE _DUMP = false ;
if ( ! Module [ 'print' ] ) {
Module [ 'print' ] = ( TRY _USE _DUMP && ( typeof ( dump ) !== "undefined" ) ? ( function ( x ) {
dump ( x ) ;
} ) : ( function ( x ) {
// self.postMessage(x); // enable this if you want stdout to be sent as messages
} ) ) ;
}
Module [ 'load' ] = importScripts ;
}
if ( ! ENVIRONMENT _IS _WORKER && ! ENVIRONMENT _IS _WEB && ! ENVIRONMENT _IS _NODE && ! ENVIRONMENT _IS _SHELL ) {
// Unreachable because SHELL is dependant on the others
throw 'Unknown runtime environment. Where are we?' ;
}
function globalEval ( x ) {
eval . call ( null , x ) ;
}
if ( ! Module [ 'load' ] == 'undefined' && Module [ 'read' ] ) {
Module [ 'load' ] = function ( f ) {
globalEval ( Module [ 'read' ] ( f ) ) ;
} ;
}
if ( ! Module [ 'print' ] ) {
Module [ 'print' ] = function ( ) { } ;
}
if ( ! Module [ 'printErr' ] ) {
Module [ 'printErr' ] = Module [ 'print' ] ;
}
if ( ! Module [ 'arguments' ] ) {
Module [ 'arguments' ] = [ ] ;
}
// *** Environment setup code ***
// Closure helpers
Module . print = Module [ 'print' ] ;
Module . printErr = Module [ 'printErr' ] ;
// Callbacks
if ( ! Module [ 'preRun' ] ) Module [ 'preRun' ] = [ ] ;
if ( ! Module [ 'postRun' ] ) Module [ 'postRun' ] = [ ] ;
// === Auto-generated preamble library stuff ===
//========================================
// Runtime code shared with compiler
//========================================
var Runtime = {
stackSave : function ( ) {
return STACKTOP ;
} ,
stackRestore : function ( stackTop ) {
STACKTOP = stackTop ;
} ,
forceAlign : function ( target , quantum ) {
quantum = quantum || 4 ;
if ( quantum == 1 ) return target ;
if ( isNumber ( target ) && isNumber ( quantum ) ) {
return Math . ceil ( target / quantum ) * quantum ;
} else if ( isNumber ( quantum ) && isPowerOfTwo ( quantum ) ) {
var logg = log2 ( quantum ) ;
return '((((' + target + ')+' + ( quantum - 1 ) + ')>>' + logg + ')<<' + logg + ')' ;
}
return 'Math.ceil((' + target + ')/' + quantum + ')*' + quantum ;
} ,
isNumberType : function ( type ) {
return type in Runtime . INT _TYPES || type in Runtime . FLOAT _TYPES ;
} ,
isPointerType : function isPointerType ( type ) {
return type [ type . length - 1 ] == '*' ;
} ,
isStructType : function isStructType ( type ) {
if ( isPointerType ( type ) ) return false ;
if ( isArrayType ( type ) ) return true ;
if ( /<?{ ?[^}]* ?}>?/ . test ( type ) ) return true ; // { i32, i8 } etc. - anonymous struct types
// See comment in isStructPointerType()
return type [ 0 ] == '%' ;
} ,
INT _TYPES : { "i1" : 0 , "i8" : 0 , "i16" : 0 , "i32" : 0 , "i64" : 0 } ,
FLOAT _TYPES : { "float" : 0 , "double" : 0 } ,
or64 : function ( x , y ) {
var l = ( x | 0 ) | ( y | 0 ) ;
var h = ( Math . round ( x / 4294967296 ) | Math . round ( y / 4294967296 ) ) * 4294967296 ;
return l + h ;
} ,
and64 : function ( x , y ) {
var l = ( x | 0 ) & ( y | 0 ) ;
var h = ( Math . round ( x / 4294967296 ) & Math . round ( y / 4294967296 ) ) * 4294967296 ;
return l + h ;
} ,
xor64 : function ( x , y ) {
var l = ( x | 0 ) ^ ( y | 0 ) ;
var h = ( Math . round ( x / 4294967296 ) ^ Math . round ( y / 4294967296 ) ) * 4294967296 ;
return l + h ;
} ,
getNativeTypeSize : function ( type , quantumSize ) {
if ( Runtime . QUANTUM _SIZE == 1 ) return 1 ;
var size = {
'%i1' : 1 ,
'%i8' : 1 ,
'%i16' : 2 ,
'%i32' : 4 ,
'%i64' : 8 ,
"%float" : 4 ,
"%double" : 8
} [ '%' + type ] ; // add '%' since float and double confuse Closure compiler as keys, and also spidermonkey as a compiler will remove 's from '_i8' etc
if ( ! size ) {
if ( type . charAt ( type . length - 1 ) == '*' ) {
size = Runtime . QUANTUM _SIZE ; // A pointer
} else if ( type [ 0 ] == 'i' ) {
var bits = parseInt ( type . substr ( 1 ) ) ;
assert ( bits % 8 == 0 ) ;
size = bits / 8 ;
}
}
return size ;
} ,
getNativeFieldSize : function ( type ) {
return Math . max ( Runtime . getNativeTypeSize ( type ) , Runtime . QUANTUM _SIZE ) ;
} ,
dedup : function dedup ( items , ident ) {
var seen = { } ;
if ( ident ) {
return items . filter ( function ( item ) {
if ( seen [ item [ ident ] ] ) return false ;
seen [ item [ ident ] ] = true ;
return true ;
} ) ;
} else {
return items . filter ( function ( item ) {
if ( seen [ item ] ) return false ;
seen [ item ] = true ;
return true ;
} ) ;
}
} ,
set : function set ( ) {
var args = typeof arguments [ 0 ] === 'object' ? arguments [ 0 ] : arguments ;
var ret = { } ;
for ( var i = 0 ; i < args . length ; i ++ ) {
ret [ args [ i ] ] = 0 ;
}
return ret ;
} ,
STACK _ALIGN : 8 ,
getAlignSize : function ( type , size , vararg ) {
// we align i64s and doubles on 64-bit boundaries, unlike x86
if ( type == 'i64' || type == 'double' || vararg ) return 8 ;
if ( ! type ) return Math . min ( size , 8 ) ; // align structures internally to 64 bits
return Math . min ( size || ( type ? Runtime . getNativeFieldSize ( type ) : 0 ) , Runtime . QUANTUM _SIZE ) ;
} ,
calculateStructAlignment : function calculateStructAlignment ( type ) {
type . flatSize = 0 ;
type . alignSize = 0 ;
var diffs = [ ] ;
var prev = - 1 ;
type . flatIndexes = type . fields . map ( function ( field ) {
var size , alignSize ;
if ( Runtime . isNumberType ( field ) || Runtime . isPointerType ( field ) ) {
size = Runtime . getNativeTypeSize ( field ) ; // pack char; char; in structs, also char[X]s.
alignSize = Runtime . getAlignSize ( field , size ) ;
} else if ( Runtime . isStructType ( field ) ) {
size = Types . types [ field ] . flatSize ;
alignSize = Runtime . getAlignSize ( null , Types . types [ field ] . alignSize ) ;
} else if ( field [ 0 ] == 'b' ) {
// bN, large number field, like a [N x i8]
size = field . substr ( 1 ) | 0 ;
alignSize = 1 ;
} else {
throw 'Unclear type in struct: ' + field + ', in ' + type . name _ + ' :: ' + dump ( Types . types [ type . name _ ] ) ;
}
if ( type . packed ) alignSize = 1 ;
type . alignSize = Math . max ( type . alignSize , alignSize ) ;
var curr = Runtime . alignMemory ( type . flatSize , alignSize ) ; // if necessary, place this on aligned memory
type . flatSize = curr + size ;
if ( prev >= 0 ) {
diffs . push ( curr - prev ) ;
}
prev = curr ;
return curr ;
} ) ;
type . flatSize = Runtime . alignMemory ( type . flatSize , type . alignSize ) ;
if ( diffs . length == 0 ) {
type . flatFactor = type . flatSize ;
} else if ( Runtime . dedup ( diffs ) . length == 1 ) {
type . flatFactor = diffs [ 0 ] ;
}
type . needsFlattening = ( type . flatFactor != 1 ) ;
return type . flatIndexes ;
} ,
generateStructInfo : function ( struct , typeName , offset ) {
var type , alignment ;
if ( typeName ) {
offset = offset || 0 ;
type = ( typeof Types === 'undefined' ? Runtime . typeInfo : Types . types ) [ typeName ] ;
if ( ! type ) return null ;
if ( type . fields . length != struct . length ) {
printErr ( 'Number of named fields must match the type for ' + typeName + ': possibly duplicate struct names. Cannot return structInfo' ) ;
return null ;
}
alignment = type . flatIndexes ;
} else {
var type = { fields : struct . map ( function ( item ) { return item [ 0 ] } ) } ;
alignment = Runtime . calculateStructAlignment ( type ) ;
}
var ret = {
_ _size _ _ : type . flatSize
} ;
if ( typeName ) {
struct . forEach ( function ( item , i ) {
if ( typeof item === 'string' ) {
ret [ item ] = alignment [ i ] + offset ;
} else {
// embedded struct
var key ;
for ( var k in item ) key = k ;
ret [ key ] = Runtime . generateStructInfo ( item [ key ] , type . fields [ i ] , alignment [ i ] ) ;
}
} ) ;
} else {
struct . forEach ( function ( item , i ) {
ret [ item [ 1 ] ] = alignment [ i ] ;
} ) ;
}
return ret ;
} ,
dynCall : function ( sig , ptr , args ) {
if ( args && args . length ) {
if ( ! args . splice ) args = Array . prototype . slice . call ( args ) ;
args . splice ( 0 , 0 , ptr ) ;
return Module [ 'dynCall_' + sig ] . apply ( null , args ) ;
} else {
return Module [ 'dynCall_' + sig ] . call ( null , ptr ) ;
}
} ,
functionPointers : [ ] ,
addFunction : function ( func ) {
for ( var i = 0 ; i < Runtime . functionPointers . length ; i ++ ) {
if ( ! Runtime . functionPointers [ i ] ) {
Runtime . functionPointers [ i ] = func ;
return 2 + 2 * i ;
}
}
throw 'Finished up all reserved function pointers. Use a higher value for RESERVED_FUNCTION_POINTERS.' ;
} ,
removeFunction : function ( index ) {
Runtime . functionPointers [ ( index - 2 ) / 2 ] = null ;
} ,
warnOnce : function ( text ) {
if ( ! Runtime . warnOnce . shown ) Runtime . warnOnce . shown = { } ;
if ( ! Runtime . warnOnce . shown [ text ] ) {
Runtime . warnOnce . shown [ text ] = 1 ;
Module . printErr ( text ) ;
}
} ,
funcWrappers : { } ,
getFuncWrapper : function ( func , sig ) {
assert ( sig ) ;
if ( ! Runtime . funcWrappers [ func ] ) {
Runtime . funcWrappers [ func ] = function ( ) {
return Runtime . dynCall ( sig , func , arguments ) ;
} ;
}
return Runtime . funcWrappers [ func ] ;
} ,
UTF8Processor : function ( ) {
var buffer = [ ] ;
var needed = 0 ;
this . processCChar = function ( code ) {
code = code & 0xff ;
if ( needed ) {
buffer . push ( code ) ;
needed -- ;
}
if ( buffer . length == 0 ) {
if ( code < 128 ) return String . fromCharCode ( code ) ;
buffer . push ( code ) ;
if ( code > 191 && code < 224 ) {
needed = 1 ;
} else {
needed = 2 ;
}
return '' ;
}
if ( needed > 0 ) return '' ;
var c1 = buffer [ 0 ] ;
var c2 = buffer [ 1 ] ;
var c3 = buffer [ 2 ] ;
var ret ;
if ( c1 > 191 && c1 < 224 ) {
ret = String . fromCharCode ( ( ( c1 & 31 ) << 6 ) | ( c2 & 63 ) ) ;
} else {
ret = String . fromCharCode ( ( ( c1 & 15 ) << 12 ) | ( ( c2 & 63 ) << 6 ) | ( c3 & 63 ) ) ;
}
buffer . length = 0 ;
return ret ;
}
this . processJSString = function ( string ) {
string = unescape ( encodeURIComponent ( string ) ) ;
var ret = [ ] ;
for ( var i = 0 ; i < string . length ; i ++ ) {
ret . push ( string . charCodeAt ( i ) ) ;
}
return ret ;
}
} ,
stackAlloc : function ( size ) { var ret = STACKTOP ; STACKTOP = ( STACKTOP + size ) | 0 ; STACKTOP = ( ( ( ( STACKTOP ) + 7 ) >> 3 ) << 3 ) ; return ret ; } ,
staticAlloc : function ( size ) { var ret = STATICTOP ; STATICTOP = ( STATICTOP + size ) | 0 ; STATICTOP = ( ( ( ( STATICTOP ) + 7 ) >> 3 ) << 3 ) ; return ret ; } ,
dynamicAlloc : function ( size ) { var ret = DYNAMICTOP ; DYNAMICTOP = ( DYNAMICTOP + size ) | 0 ; DYNAMICTOP = ( ( ( ( DYNAMICTOP ) + 7 ) >> 3 ) << 3 ) ; if ( DYNAMICTOP >= TOTAL _MEMORY ) enlargeMemory ( ) ; ; return ret ; } ,
alignMemory : function ( size , quantum ) { var ret = size = Math . ceil ( ( size ) / ( quantum ? quantum : 8 ) ) * ( quantum ? quantum : 8 ) ; return ret ; } ,
makeBigInt : function ( low , high , unsigned ) { var ret = ( unsigned ? ( ( + ( ( ( low ) >>> ( 0 ) ) ) ) + ( ( + ( ( ( high ) >>> ( 0 ) ) ) ) * ( + ( 4294967296 ) ) ) ) : ( ( + ( ( ( low ) >>> ( 0 ) ) ) ) + ( ( + ( ( ( high ) | ( 0 ) ) ) ) * ( + ( 4294967296 ) ) ) ) ) ; return ret ; } ,
GLOBAL _BASE : 8 ,
QUANTUM _SIZE : 4 ,
_ _dummy _ _ : 0
}
//========================================
// Runtime essentials
//========================================
var _ _THREW _ _ = 0 ; // Used in checking for thrown exceptions.
var ABORT = false ; // whether we are quitting the application. no code should run after this. set in exit() and abort()
var undef = 0 ;
// tempInt is used for 32-bit signed values or smaller. tempBigInt is used
// for 32-bit unsigned values or more than 32 bits. TODO: audit all uses of tempInt
var tempValue , tempInt , tempBigInt , tempInt2 , tempBigInt2 , tempPair , tempBigIntI , tempBigIntR , tempBigIntS , tempBigIntP , tempBigIntD ;
var tempI64 , tempI64b ;
var tempRet0 , tempRet1 , tempRet2 , tempRet3 , tempRet4 , tempRet5 , tempRet6 , tempRet7 , tempRet8 , tempRet9 ;
function abort ( text ) {
Module . print ( text + ':\n' + ( new Error ) . stack ) ;
ABORT = true ;
throw "Assertion: " + text ;
}
function assert ( condition , text ) {
if ( ! condition ) {
abort ( 'Assertion failed: ' + text ) ;
}
}
var globalScope = this ;
// C calling interface. A convenient way to call C functions (in C files, or
// defined with extern "C").
//
// Note: LLVM optimizations can inline and remove functions, after which you will not be
// able to call them. Closure can also do so. To avoid that, add your function to
// the exports using something like
//
// -s EXPORTED_FUNCTIONS='["_main", "_myfunc"]'
//
// @param ident The name of the C function (note that C++ functions will be name-mangled - use extern "C")
// @param returnType The return type of the function, one of the JS types 'number', 'string' or 'array' (use 'number' for any C pointer, and
// 'array' for JavaScript arrays and typed arrays).
// @param argTypes An array of the types of arguments for the function (if there are no arguments, this can be ommitted). Types are as in returnType,
// except that 'array' is not possible (there is no way for us to know the length of the array)
// @param args An array of the arguments to the function, as native JS values (as in returnType)
// Note that string arguments will be stored on the stack (the JS string will become a C string on the stack).
// @return The return value, as a native JS value (as in returnType)
function ccall ( ident , returnType , argTypes , args ) {
return ccallFunc ( getCFunc ( ident ) , returnType , argTypes , args ) ;
}
Module [ "ccall" ] = ccall ;
// Returns the C function with a specified identifier (for C++, you need to do manual name mangling)
function getCFunc ( ident ) {
try {
var func = globalScope [ 'Module' ] [ '_' + ident ] ; // closure exported function
if ( ! func ) func = eval ( '_' + ident ) ; // explicit lookup
} catch ( e ) {
}
assert ( func , 'Cannot call unknown function ' + ident + ' (perhaps LLVM optimizations or closure removed it?)' ) ;
return func ;
}
// Internal function that does a C call using a function, not an identifier
function ccallFunc ( func , returnType , argTypes , args ) {
var stack = 0 ;
function toC ( value , type ) {
if ( type == 'string' ) {
if ( value === null || value === undefined || value === 0 ) return 0 ; // null string
if ( ! stack ) stack = Runtime . stackSave ( ) ;
var ret = Runtime . stackAlloc ( value . length + 1 ) ;
writeStringToMemory ( value , ret ) ;
return ret ;
} else if ( type == 'array' ) {
if ( ! stack ) stack = Runtime . stackSave ( ) ;
var ret = Runtime . stackAlloc ( value . length ) ;
writeArrayToMemory ( value , ret ) ;
return ret ;
}
return value ;
}
function fromC ( value , type ) {
if ( type == 'string' ) {
return Pointer _stringify ( value ) ;
}
assert ( type != 'array' ) ;
return value ;
}
var i = 0 ;
var cArgs = args ? args . map ( function ( arg ) {
return toC ( arg , argTypes [ i ++ ] ) ;
} ) : [ ] ;
var ret = fromC ( func . apply ( null , cArgs ) , returnType ) ;
if ( stack ) Runtime . stackRestore ( stack ) ;
return ret ;
}
// Returns a native JS wrapper for a C function. This is similar to ccall, but
// returns a function you can call repeatedly in a normal way. For example:
//
// var my_function = cwrap('my_c_function', 'number', ['number', 'number']);
// alert(my_function(5, 22));
// alert(my_function(99, 12));
//
function cwrap ( ident , returnType , argTypes ) {
var func = getCFunc ( ident ) ;
return function ( ) {
return ccallFunc ( func , returnType , argTypes , Array . prototype . slice . call ( arguments ) ) ;
}
}
Module [ "cwrap" ] = cwrap ;
// Sets a value in memory in a dynamic way at run-time. Uses the
// type data. This is the same as makeSetValue, except that
// makeSetValue is done at compile-time and generates the needed
// code then, whereas this function picks the right code at
// run-time.
// Note that setValue and getValue only do *aligned* writes and reads!
// Note that ccall uses JS types as for defining types, while setValue and
// getValue need LLVM types ('i8', 'i32') - this is a lower-level operation
function setValue ( ptr , value , type , noSafe ) {
type = type || 'i8' ;
if ( type . charAt ( type . length - 1 ) === '*' ) type = 'i32' ; // pointers are 32-bit
switch ( type ) {
case 'i1' : HEAP8 [ ( ptr ) ] = value ; break ;
case 'i8' : HEAP8 [ ( ptr ) ] = value ; break ;
case 'i16' : HEAP16 [ ( ( ptr ) >> 1 ) ] = value ; break ;
case 'i32' : HEAP32 [ ( ( ptr ) >> 2 ) ] = value ; break ;
case 'i64' : ( tempI64 = [ value >>> 0 , Math . min ( Math . floor ( ( value ) / ( + ( 4294967296 ) ) ) , ( + ( 4294967295 ) ) ) >>> 0 ] , HEAP32 [ ( ( ptr ) >> 2 ) ] = tempI64 [ 0 ] , HEAP32 [ ( ( ( ptr ) + ( 4 ) ) >> 2 ) ] = tempI64 [ 1 ] ) ; break ;
case 'float' : HEAPF32 [ ( ( ptr ) >> 2 ) ] = value ; break ;
case 'double' : HEAPF64 [ ( ( ptr ) >> 3 ) ] = value ; break ;
default : abort ( 'invalid type for setValue: ' + type ) ;
}
}
Module [ 'setValue' ] = setValue ;
// Parallel to setValue.
function getValue ( ptr , type , noSafe ) {
type = type || 'i8' ;
if ( type . charAt ( type . length - 1 ) === '*' ) type = 'i32' ; // pointers are 32-bit
switch ( type ) {
case 'i1' : return HEAP8 [ ( ptr ) ] ;
case 'i8' : return HEAP8 [ ( ptr ) ] ;
case 'i16' : return HEAP16 [ ( ( ptr ) >> 1 ) ] ;
case 'i32' : return HEAP32 [ ( ( ptr ) >> 2 ) ] ;
case 'i64' : return HEAP32 [ ( ( ptr ) >> 2 ) ] ;
case 'float' : return HEAPF32 [ ( ( ptr ) >> 2 ) ] ;
case 'double' : return HEAPF64 [ ( ( ptr ) >> 3 ) ] ;
default : abort ( 'invalid type for setValue: ' + type ) ;
}
return null ;
}
Module [ 'getValue' ] = getValue ;
var ALLOC _NORMAL = 0 ; // Tries to use _malloc()
var ALLOC _STACK = 1 ; // Lives for the duration of the current function call
var ALLOC _STATIC = 2 ; // Cannot be freed
var ALLOC _DYNAMIC = 3 ; // Cannot be freed except through sbrk
var ALLOC _NONE = 4 ; // Do not allocate
Module [ 'ALLOC_NORMAL' ] = ALLOC _NORMAL ;
Module [ 'ALLOC_STACK' ] = ALLOC _STACK ;
Module [ 'ALLOC_STATIC' ] = ALLOC _STATIC ;
Module [ 'ALLOC_DYNAMIC' ] = ALLOC _DYNAMIC ;
Module [ 'ALLOC_NONE' ] = ALLOC _NONE ;
// allocate(): This is for internal use. You can use it yourself as well, but the interface
// is a little tricky (see docs right below). The reason is that it is optimized
// for multiple syntaxes to save space in generated code. So you should
// normally not use allocate(), and instead allocate memory using _malloc(),
// initialize it with setValue(), and so forth.
// @slab: An array of data, or a number. If a number, then the size of the block to allocate,
// in *bytes* (note that this is sometimes confusing: the next parameter does not
// affect this!)
// @types: Either an array of types, one for each byte (or 0 if no type at that position),
// or a single type which is used for the entire block. This only matters if there
// is initial data - if @slab is a number, then this does not matter at all and is
// ignored.
// @allocator: How to allocate memory, see ALLOC_*
function allocate ( slab , types , allocator , ptr ) {
var zeroinit , size ;
if ( typeof slab === 'number' ) {
zeroinit = true ;
size = slab ;
} else {
zeroinit = false ;
size = slab . length ;
}
var singleType = typeof types === 'string' ? types : null ;
var ret ;
if ( allocator == ALLOC _NONE ) {
ret = ptr ;
} else {
ret = [ _malloc , Runtime . stackAlloc , Runtime . staticAlloc , Runtime . dynamicAlloc ] [ allocator === undefined ? ALLOC _STATIC : allocator ] ( Math . max ( size , singleType ? 1 : types . length ) ) ;
}
if ( zeroinit ) {
var ptr = ret , stop ;
assert ( ( ret & 3 ) == 0 ) ;
stop = ret + ( size & ~ 3 ) ;
for ( ; ptr < stop ; ptr += 4 ) {
HEAP32 [ ( ( ptr ) >> 2 ) ] = 0 ;
}
stop = ret + size ;
while ( ptr < stop ) {
HEAP8 [ ( ( ptr ++ ) | 0 ) ] = 0 ;
}
return ret ;
}
if ( singleType === 'i8' ) {
if ( slab . subarray || slab . slice ) {
HEAPU8 . set ( slab , ret ) ;
} else {
HEAPU8 . set ( new Uint8Array ( slab ) , ret ) ;
}
return ret ;
}
var i = 0 , type , typeSize , previousType ;
while ( i < size ) {
var curr = slab [ i ] ;
if ( typeof curr === 'function' ) {
curr = Runtime . getFunctionIndex ( curr ) ;
}
type = singleType || types [ i ] ;
if ( type === 0 ) {
i ++ ;
continue ;
}
if ( type == 'i64' ) type = 'i32' ; // special case: we have one i32 here, and one i32 later
setValue ( ret + i , curr , type ) ;
// no need to look up size unless type changes, so cache it
if ( previousType !== type ) {
typeSize = Runtime . getNativeTypeSize ( type ) ;
previousType = type ;
}
i += typeSize ;
}
return ret ;
}
Module [ 'allocate' ] = allocate ;
function Pointer _stringify ( ptr , /* optional */ length ) {
// Find the length, and check for UTF while doing so
var hasUtf = false ;
var t ;
var i = 0 ;
while ( 1 ) {
t = HEAPU8 [ ( ( ( ptr ) + ( i ) ) | 0 ) ] ;
if ( t >= 128 ) hasUtf = true ;
else if ( t == 0 && ! length ) break ;
i ++ ;
if ( length && i == length ) break ;
}
if ( ! length ) length = i ;
var ret = '' ;
if ( ! hasUtf ) {
var MAX _CHUNK = 1024 ; // split up into chunks, because .apply on a huge string can overflow the stack
var curr ;
while ( length > 0 ) {
curr = String . fromCharCode . apply ( String , HEAPU8 . subarray ( ptr , ptr + Math . min ( length , MAX _CHUNK ) ) ) ;
ret = ret ? ret + curr : curr ;
ptr += MAX _CHUNK ;
length -= MAX _CHUNK ;
}
return ret ;
}
var utf8 = new Runtime . UTF8Processor ( ) ;
for ( i = 0 ; i < length ; i ++ ) {
t = HEAPU8 [ ( ( ( ptr ) + ( i ) ) | 0 ) ] ;
ret += utf8 . processCChar ( t ) ;
}
return ret ;
}
Module [ 'Pointer_stringify' ] = Pointer _stringify ;
// Memory management
var PAGE _SIZE = 4096 ;
function alignMemoryPage ( x ) {
return ( ( x + 4095 ) >> 12 ) << 12 ;
}
var HEAP ;
var HEAP8 , HEAPU8 , HEAP16 , HEAPU16 , HEAP32 , HEAPU32 , HEAPF32 , HEAPF64 ;
var STATIC _BASE = 0 , STATICTOP = 0 , staticSealed = false ; // static area
var STACK _BASE = 0 , STACKTOP = 0 , STACK _MAX = 0 ; // stack area
var DYNAMIC _BASE = 0 , DYNAMICTOP = 0 ; // dynamic area handled by sbrk
function enlargeMemory ( ) {
abort ( 'Cannot enlarge memory arrays in asm.js. Either (1) compile with -s TOTAL_MEMORY=X with X higher than the current value, or (2) set Module.TOTAL_MEMORY before the program runs.' ) ;
}
var TOTAL _STACK = Module [ 'TOTAL_STACK' ] || 5242880 ;
var TOTAL _MEMORY = Module [ 'TOTAL_MEMORY' ] || 16777216 ;
var FAST _MEMORY = Module [ 'FAST_MEMORY' ] || 2097152 ;
// Initialize the runtime's memory
// check for full engine support (use string 'subarray' to avoid closure compiler confusion)
assert ( ! ! Int32Array && ! ! Float64Array && ! ! ( new Int32Array ( 1 ) [ 'subarray' ] ) && ! ! ( new Int32Array ( 1 ) [ 'set' ] ) ,
'Cannot fallback to non-typed array case: Code is too specialized' ) ;
var buffer = new ArrayBuffer ( TOTAL _MEMORY ) ;
HEAP8 = new Int8Array ( buffer ) ;
HEAP16 = new Int16Array ( buffer ) ;
HEAP32 = new Int32Array ( buffer ) ;
HEAPU8 = new Uint8Array ( buffer ) ;
HEAPU16 = new Uint16Array ( buffer ) ;
HEAPU32 = new Uint32Array ( buffer ) ;
HEAPF32 = new Float32Array ( buffer ) ;
HEAPF64 = new Float64Array ( buffer ) ;
// Endianness check (note: assumes compiler arch was little-endian)
HEAP32 [ 0 ] = 255 ;
assert ( HEAPU8 [ 0 ] === 255 && HEAPU8 [ 3 ] === 0 , 'Typed arrays 2 must be run on a little-endian system' ) ;
Module [ 'HEAP' ] = HEAP ;
Module [ 'HEAP8' ] = HEAP8 ;
Module [ 'HEAP16' ] = HEAP16 ;
Module [ 'HEAP32' ] = HEAP32 ;
Module [ 'HEAPU8' ] = HEAPU8 ;
Module [ 'HEAPU16' ] = HEAPU16 ;
Module [ 'HEAPU32' ] = HEAPU32 ;
Module [ 'HEAPF32' ] = HEAPF32 ;
Module [ 'HEAPF64' ] = HEAPF64 ;
function callRuntimeCallbacks ( callbacks ) {
while ( callbacks . length > 0 ) {
var callback = callbacks . shift ( ) ;
if ( typeof callback == 'function' ) {
callback ( ) ;
continue ;
}
var func = callback . func ;
if ( typeof func === 'number' ) {
if ( callback . arg === undefined ) {
Runtime . dynCall ( 'v' , func ) ;
} else {
Runtime . dynCall ( 'vi' , func , [ callback . arg ] ) ;
}
} else {
func ( callback . arg === undefined ? null : callback . arg ) ;
}
}
}
var _ _ATINIT _ _ = [ ] ; // functions called during startup
var _ _ATMAIN _ _ = [ ] ; // functions called when main() is to be run
var _ _ATEXIT _ _ = [ ] ; // functions called during shutdown
var runtimeInitialized = false ;
function ensureInitRuntime ( ) {
if ( runtimeInitialized ) return ;
runtimeInitialized = true ;
callRuntimeCallbacks ( _ _ATINIT _ _ ) ;
}
function preMain ( ) {
callRuntimeCallbacks ( _ _ATMAIN _ _ ) ;
}
function exitRuntime ( ) {
callRuntimeCallbacks ( _ _ATEXIT _ _ ) ;
}
// Tools
// This processes a JS string into a C-line array of numbers, 0-terminated.
// For LLVM-originating strings, see parser.js:parseLLVMString function
function intArrayFromString ( stringy , dontAddNull , length /* optional */ ) {
var ret = ( new Runtime . UTF8Processor ( ) ) . processJSString ( stringy ) ;
if ( length ) {
ret . length = length ;
}
if ( ! dontAddNull ) {
ret . push ( 0 ) ;
}
return ret ;
}
Module [ 'intArrayFromString' ] = intArrayFromString ;
function intArrayToString ( array ) {
var ret = [ ] ;
for ( var i = 0 ; i < array . length ; i ++ ) {
var chr = array [ i ] ;
if ( chr > 0xFF ) {
chr &= 0xFF ;
}
ret . push ( String . fromCharCode ( chr ) ) ;
}
return ret . join ( '' ) ;
}
Module [ 'intArrayToString' ] = intArrayToString ;
// Write a Javascript array to somewhere in the heap
function writeStringToMemory ( string , buffer , dontAddNull ) {
var array = intArrayFromString ( string , dontAddNull ) ;
var i = 0 ;
while ( i < array . length ) {
var chr = array [ i ] ;
HEAP8 [ ( ( ( buffer ) + ( i ) ) | 0 ) ] = chr
i = i + 1 ;
}
}
Module [ 'writeStringToMemory' ] = writeStringToMemory ;
function writeArrayToMemory ( array , buffer ) {
for ( var i = 0 ; i < array . length ; i ++ ) {
HEAP8 [ ( ( ( buffer ) + ( i ) ) | 0 ) ] = array [ i ] ;
}
}
Module [ 'writeArrayToMemory' ] = writeArrayToMemory ;
function unSign ( value , bits , ignore , sig ) {
if ( value >= 0 ) {
return value ;
}
return bits <= 32 ? 2 * Math . abs ( 1 << ( bits - 1 ) ) + value // Need some trickery, since if bits == 32, we are right at the limit of the bits JS uses in bitshifts
: Math . pow ( 2 , bits ) + value ;
}
function reSign ( value , bits , ignore , sig ) {
if ( value <= 0 ) {
return value ;
}
var half = bits <= 32 ? Math . abs ( 1 << ( bits - 1 ) ) // abs is needed if bits == 32
: Math . pow ( 2 , bits - 1 ) ;
if ( value >= half && ( bits <= 32 || value > half ) ) { // for huge values, we can hit the precision limit and always get true here. so don't do that
// but, in general there is no perfect solution here. With 64-bit ints, we get rounding and errors
// TODO: In i64 mode 1, resign the two parts separately and safely
value = - 2 * half + value ; // Cannot bitshift half, as it may be at the limit of the bits JS uses in bitshifts
}
return value ;
}
if ( ! Math [ 'imul' ] ) Math [ 'imul' ] = function ( a , b ) {
var ah = a >>> 16 ;
var al = a & 0xffff ;
var bh = b >>> 16 ;
var bl = b & 0xffff ;
return ( al * bl + ( ( ah * bl + al * bh ) << 16 ) ) | 0 ;
} ;
// A counter of dependencies for calling run(). If we need to
// do asynchronous work before running, increment this and
// decrement it. Incrementing must happen in a place like
// PRE_RUN_ADDITIONS (used by emcc to add file preloading).
// Note that you can add dependencies in preRun, even though
// it happens right before run - run will be postponed until
// the dependencies are met.
var runDependencies = 0 ;
var runDependencyTracking = { } ;
var calledInit = false , calledRun = false ;
var runDependencyWatcher = null ;
function addRunDependency ( id ) {
runDependencies ++ ;
if ( Module [ 'monitorRunDependencies' ] ) {
Module [ 'monitorRunDependencies' ] ( runDependencies ) ;
}
if ( id ) {
assert ( ! runDependencyTracking [ id ] ) ;
runDependencyTracking [ id ] = 1 ;
} else {
Module . printErr ( 'warning: run dependency added without ID' ) ;
}
}
Module [ 'addRunDependency' ] = addRunDependency ;
function removeRunDependency ( id ) {
runDependencies -- ;
if ( Module [ 'monitorRunDependencies' ] ) {
Module [ 'monitorRunDependencies' ] ( runDependencies ) ;
}
if ( id ) {
assert ( runDependencyTracking [ id ] ) ;
delete runDependencyTracking [ id ] ;
} else {
Module . printErr ( 'warning: run dependency removed without ID' ) ;
}
if ( runDependencies == 0 ) {
if ( runDependencyWatcher !== null ) {
clearInterval ( runDependencyWatcher ) ;
runDependencyWatcher = null ;
}
// If run has never been called, and we should call run (INVOKE_RUN is true, and Module.noInitialRun is not false)
if ( ! calledRun && shouldRunNow ) run ( ) ;
}
}
Module [ 'removeRunDependency' ] = removeRunDependency ;
Module [ "preloadedImages" ] = { } ; // maps url to image data
Module [ "preloadedAudios" ] = { } ; // maps url to audio data
function addPreRun ( func ) {
if ( ! Module [ 'preRun' ] ) Module [ 'preRun' ] = [ ] ;
else if ( typeof Module [ 'preRun' ] == 'function' ) Module [ 'preRun' ] = [ Module [ 'preRun' ] ] ;
Module [ 'preRun' ] . push ( func ) ;
}
var awaitingMemoryInitializer = false ;
function loadMemoryInitializer ( filename ) {
function applyData ( data ) {
HEAPU8 . set ( data , STATIC _BASE ) ;
runPostSets ( ) ;
}
// always do this asynchronously, to keep shell and web as similar as possible
addPreRun ( function ( ) {
if ( ENVIRONMENT _IS _NODE || ENVIRONMENT _IS _SHELL ) {
applyData ( Module [ 'readBinary' ] ( filename ) ) ;
} else {
Browser . asyncLoad ( filename , function ( data ) {
applyData ( data ) ;
} , function ( data ) {
throw 'could not load memory initializer ' + filename ;
} ) ;
}
} ) ;
awaitingMemoryInitializer = false ;
}
// === Body ===
STATIC _BASE = 8 ;
STATICTOP = STATIC _BASE + 32536 ;
/* memory initializer */ allocate ( [ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 176 , 160 , 14 , 254 , 211 , 201 , 134 , 255 , 158 , 24 , 143 , 0 , 127 , 105 , 53 , 0 , 96 , 12 , 189 , 0 , 167 , 215 , 251 , 255 , 159 , 76 , 128 , 254 , 106 , 101 , 225 , 255 , 30 , 252 , 4 , 0 , 146 , 12 , 174 , 0 , 89 , 241 , 178 , 254 , 10 , 229 , 166 , 255 , 123 , 221 , 42 , 254 , 30 , 20 , 212 , 0 , 82 , 128 , 3 , 0 , 48 , 209 , 243 , 0 , 119 , 121 , 64 , 255 , 50 , 227 , 156 , 255 , 0 , 110 , 197 , 1 , 103 , 27 , 144 , 0 , 182 , 120 , 89 , 255 , 133 , 114 , 211 , 0 , 189 , 110 , 21 , 255 , 15 , 10 , 106 , 0 , 41 , 192 , 1 , 0 , 152 , 232 , 121 , 255 , 188 , 60 , 160 , 255 , 153 , 113 , 206 , 255 , 0 , 183 , 226 , 254 , 180 , 13 , 72 , 255 , 133 , 59 , 140 , 1 , 189 , 241 , 36 , 255 , 248 , 37 , 195 , 1 , 96 , 220 , 55 , 0 , 183 , 76 , 62 , 255 , 195 , 66 , 61 , 0 , 50 , 76 , 164 , 1 , 225 , 164 , 76 , 255 , 76 , 61 , 163 , 255 , 117 , 62 , 31 , 0 , 81 , 145 , 64 , 255 , 118 , 65 , 14 , 0 , 162 , 115 , 214 , 255 , 6 , 138 , 46 , 0 , 124 , 230 , 244 , 255 , 10 , 138 , 143 , 0 , 52 , 26 , 194 , 0 , 184 , 244 , 76 , 0 , 129 , 143 , 41 , 1 , 190 , 244 , 19 , 255 , 123 , 170 , 122 , 255 , 98 , 129 , 68 , 0 , 121 , 213 , 147 , 0 , 86 , 101 , 30 , 255 , 161 , 103 , 155 , 0 , 140 , 89 , 67 , 255 , 239 , 229 , 190 , 1 , 67 , 11 , 181 , 0 , 198 , 240 , 137 , 254 , 238 , 69 , 188 , 255 , 234 , 113 , 60 , 255 , 37 , 255 , 57 , 255 , 69 , 178 , 182 , 254 , 128 , 208 , 179 , 0 , 118 , 26 , 125 , 254 , 3 , 7 , 214 , 255 , 241 , 50 , 77 , 255 , 85 , 203 , 197 , 255 , 211 , 135 , 250 , 255 , 25 , 48 , 100 , 255 , 187 , 213 , 180 , 254 , 17 , 88 , 105 , 0 , 83 , 209 , 158 , 1 , 5 , 115 , 98 , 0 , 4 , 174 , 60 , 254 , 171 , 55 , 110 , 255 , 217 , 181 , 17 , 255 , 20 , 188 , 170 , 0 , 146 , 156 , 102 , 254 , 87 , 214 , 174 , 255 , 114 , 122 , 155 , 1 , 233 , 44 , 170 , 0 , 127 , 8 , 239 , 1 , 214 , 236 , 234 , 0 , 175 , 5 , 219 , 0 , 49 , 106 , 61 , 255 , 6 , 66 , 208 , 255 , 2 , 106 , 110 , 255 , 81 , 234 , 19 , 255 , 215 , 107 , 192 , 255 , 67 , 151 , 238 , 0 , 19 , 42 , 108 , 255 , 229 , 85 , 113 , 1 , 50 , 68 , 135 , 255 , 17 , 106 , 9 , 0 , 50 , 103 , 1 , 255 , 80 , 1 , 168 , 1 , 35 , 152 , 30 , 255 , 16 , 168 , 185 , 1 , 56 , 89 , 232 , 255 , 101 , 210 , 252 , 0 , 41 , 250 , 71 , 0 , 204 , 170 , 79 , 255 , 14 , 46 , 239 , 255 , 80 , 77 , 239 , 0 , 189 , 214 , 75 , 255 , 17 , 141 , 249 , 0 , 38 , 80 , 76 , 255 , 190 , 85 , 117 , 0 , 86 , 228 , 170 , 0 , 156 , 216 , 208 , 1 , 195 , 207 , 164 , 255 , 150 , 66 , 76 , 255 , 175 , 225 , 16 , 255 , 141 , 80 , 98 , 1 , 76 , 219 , 242 , 0 , 198 , 162 , 114 , 0 , 46 , 218 , 152 , 0 , 155 , 43 , 241 , 254 , 155 , 160 , 104 , 255 , 178 , 9 , 252 , 254 , 100 , 110 , 212 , 0 , 14 , 5 , 167 , 0 , 233 , 239 , 163 , 255 , 28 , 151 , 157 , 1 , 101 , 146 , 10 , 255 , 254 , 158 , 70 , 254 , 71 , 249 , 228 , 0 , 88 , 30 , 50 , 0 , 68 , 58 , 160 , 255 , 191 , 24 , 104 , 1 , 129 , 66 , 129 , 255 , 192 , 50 , 85 , 255 , 8 , 179 , 138 , 255 , 38 , 250 , 201 , 0 , 115 , 80 , 160 , 0 , 131 , 230 , 113 , 0 , 125 , 88 , 147 , 0 , 90 , 68 , 199 , 0 , 253 , 76 , 158 , 0 , 28 , 255 , 118 , 0 , 113 , 250 , 254 , 0 , 66 , 75 , 46 , 0 , 230 , 218 , 43 , 0 , 229 , 120 , 186 , 1 , 148 , 68 , 43 , 0 , 136 , 124 , 238 , 1 , 187 , 107 , 197 , 255 , 84 , 53 , 246 , 255 , 51 , 116 , 254 , 255 , 51 , 187 , 165 , 0 , 2 , 17 , 175 , 0 , 66 , 84 , 160 , 1 , 247 , 58 , 30 , 0 , 35 , 65 , 53 , 254 , 69 , 236 , 191 , 0 , 45 , 134 , 245 , 1 , 163 , 123 , 221 , 0 , 32 , 110 , 20 , 255 , 52 , 23 , 165 , 0 , 186 , 214 , 71 , 0 , 233 , 176 , 96 , 0 , 242 , 239 , 54 , 1 , 57 , 89 , 138 , 0 , 83 , 0 , 84 , 255 , 136 , 160 , 100 , 0 , 92 , 142 , 120 , 254 , 104 , 124 , 190 , 0 , 181 , 177 , 62 , 255 , 250 , 41 , 85 , 0 , 152 , 130 , 42 , 1 , 96 , 252 , 246 , 0 , 151 , 151 , 63 , 254 , 239 , 133 , 62 , 0 , 32 , 56 , 156 , 0 , 45 , 167 , 189 , 255 , 142 , 133 , 179 , 1 , 131 , 86 , 211 , 0 , 187 , 179 , 150 , 254 , 250 , 170 , 14 , 255 , 68 , 113 , 21 , 255 , 222 , 186 , 59 , 255 , 66 , 7 , 241 , 1 , 69 , 6 , 72 , 0 , 86 , 156 , 108 , 254 , 55 , 167 , 89 , 0 , 109 , 52 , 219 , 254 , 13 , 176 , 23 , 255 , 196 , 44 , 106 , 255 , 239 , 149 , 71 , 255 , 164 , 140 , 125 , 255 , 159 , 173 , 1 , 0 , 51 , 41 , 231 , 0 , 145 , 62 , 33 , 0 , 138 , 111 , 93 , 1 , 185 , 83 , 69 , 0 , 144 , 115 , 46 , 0 , 97 , 151 , 16 , 255 , 24 , 228 , 26 , 0 , 49 , 217 , 226 , 0 , 113 , 75 , 234 , 254 , 193 , 153 , 12 , 255 , 182 , 48 , 96 , 255 , 14 , 13 , 26 , 0 , 128 , 195 , 249 , 254 , 69 , 193 , 59 , 0 , 132 , 37 , 81 , 254 , 125 , 106 , 60 , 0 , 214 , 240 , 169 , 1 , 164 , 227 , 66 , 0 , 210 , 163 , 78 , 0 , 37 , 52 , 151 , 0 , 99 , 77 , 26 , 0 , 238 , 156 , 213 , 255 , 213 , 192 , 209 , 1 , 73 , 46 , 84 , 0 , 20 , 65 , 41 , 1 , 54 , 206 , 79 , 0 , 201 , 131 , 146 , 254 , 170 , 111 , 24 , 255 , 177 , 33 , 50 , 254 , 171 , 38 , 203 , 255 , 78 , 247 , 116 , 0 , 209 , 221 , 153 , 0 , 133 , 128 , 178 , 1 , 58 , 44 , 25 , 0 , 201 , 39 , 59 , 1 , 189 , 19 , 252 , 0 , 49 , 229 , 210 , 1 , 117 , 187 , 117 , 0 , 181 , 179 , 184 , 1 , 0 , 114 , 219 , 0 , 48 , 94 , 147 , 0 , 245 , 41 , 56 , 0 , 125 , 13 , 204 , 254 , 244 , 173 , 119 , 0 , 44 , 221 , 32 , 254 , 84 , 234 , 20 , 0 , 249 , 160 , 198 , 1 , 236 , 126 , 234 , 255 , 143 , 62 , 221 , 0 , 129 , 89 , 214 , 255 , 55 , 139 , 5 , 254 , 68 , 20 , 191 , 255 , 14 , 204 , 178 , 1 , 35 , 195 , 217 , 0 , 47 , 51 , 206 , 1 , 38 , 246 , 165 , 0 , 206 , 27 , 6 , 254 , 158 , 87 , 36 , 0 , 217 , 52 , 146 , 255 , 125 , 123 , 215 , 255 , 85 , 60 , 31 , 255 , 171 , 13 , 7 , 0 , 218 , 245 , 88 , 254 , 252 , 35 , 60 , 0 , 55 , 214 , 160 , 255 , 133 , 101 , 56 , 0 , 224 , 32 , 19 , 254 , 147 , 64 , 234 , 0 , 26 , 145 , 162 , 1 , 114 , 118 , 125 , 0 , 248 , 252 , 250 , 0 , 101 , 94 , 196 , 255 , 198 , 141 , 226 , 254 , 51 , 42 , 182 , 0 , 135 , 12 , 9 , 254 , 109 , 172 , 210 , 255 , 197 , 236 , 194 , 1 , 241 , 65 , 154 , 0 , 48 , 156 , 47 , 255 , 153 , 67 , 55 , 255 , 218 , 165 , 34 , 254 , 74 , 180 , 179 , 0 , 218 , 66 , 71 , 1 , 88 , 122 , 99 , 0 , 212 , 181 , 219 , 255 , 92 , 42 , 231 , 255 , 239 , 0 , 154 , 0 , 245 , 77 , 183 , 255 , 94 , 81 , 170 , 1 , 18 , 213 , 216 , 0 , 171 , 93 , 71 , 0 , 52 , 94 , 248 , 0 , 18 , 151 , 161 , 254 , 197 , 209 , 66 , 255 , 174 , 244 , 15 , 254 , 162 , 48 , 183 , 0 , 49 , 61 , 240 , 254 , 182 , 93 , 195 , 0 , 199 , 228 , 6 , 1 , 200 , 5 , 17 , 255 , 137 , 45 , 237 , 255 , 108 , 148 , 4 , 0 , 90 , 79 , 23
. concat ( [ 40 , 21 , 138 , 254 , 104 , 116 , 228 , 0 , 199 , 95 , 137 , 255 , 133 , 190 , 168 , 255 , 146 , 165 , 234 , 1 , 183 , 99 , 39 , 0 , 183 , 220 , 54 , 254 , 255 , 222 , 133 , 0 , 162 , 219 , 121 , 254 , 63 , 239 , 6 , 0 , 225 , 102 , 54 , 255 , 251 , 18 , 246 , 0 , 4 , 34 , 129 , 1 , 135 , 36 , 131 , 0 , 206 , 50 , 59 , 1 , 15 , 97 , 183 , 0 , 171 , 216 , 135 , 255 , 101 , 152 , 43 , 255 , 150 , 251 , 91 , 0 , 38 , 145 , 95 , 0 , 34 , 204 , 38 , 254 , 178 , 140 , 83 , 255 , 25 , 129 , 243 , 255 , 76 , 144 , 37 , 0 , 106 , 36 , 26 , 254 , 118 , 144 , 172 , 255 , 68 , 186 , 229 , 255 , 107 , 161 , 213 , 255 , 46 , 163 , 68 , 255 , 149 , 170 , 253 , 0 , 187 , 17 , 15 , 0 , 218 , 160 , 165 , 255 , 171 , 35 , 246 , 1 , 96 , 13 , 19 , 0 , 165 , 203 , 117 , 0 , 214 , 107 , 192 , 255 , 244 , 123 , 177 , 1 , 100 , 3 , 104 , 0 , 178 , 242 , 97 , 255 , 251 , 76 , 130 , 255 , 211 , 77 , 42 , 1 , 250 , 79 , 70 , 255 , 63 , 244 , 80 , 1 , 105 , 101 , 246 , 0 , 61 , 136 , 58 , 1 , 238 , 91 , 213 , 0 , 14 , 59 , 98 , 255 , 167 , 84 , 77 , 0 , 17 , 132 , 46 , 254 , 57 , 175 , 197 , 255 , 185 , 62 , 184 , 0 , 76 , 64 , 207 , 0 , 172 , 175 , 208 , 254 , 175 , 74 , 37 , 0 , 138 , 27 , 211 , 254 , 148 , 125 , 194 , 0 , 10 , 89 , 81 , 0 , 168 , 203 , 101 , 255 , 43 , 213 , 209 , 1 , 235 , 245 , 54 , 0 , 30 , 35 , 226 , 255 , 9 , 126 , 70 , 0 , 226 , 125 , 94 , 254 , 156 , 117 , 20 , 255 , 57 , 248 , 112 , 1 , 230 , 48 , 64 , 255 , 164 , 92 , 166 , 1 , 224 , 214 , 230 , 255 , 36 , 120 , 143 , 0 , 55 , 8 , 43 , 255 , 251 , 1 , 245 , 1 , 106 , 98 , 165 , 0 , 74 , 107 , 106 , 254 , 53 , 4 , 54 , 255 , 90 , 178 , 150 , 1 , 3 , 120 , 123 , 255 , 244 , 5 , 89 , 1 , 114 , 250 , 61 , 255 , 254 , 153 , 82 , 1 , 77 , 15 , 17 , 0 , 57 , 238 , 90 , 1 , 95 , 223 , 230 , 0 , 236 , 52 , 47 , 254 , 103 , 148 , 164 , 255 , 121 , 207 , 36 , 1 , 18 , 16 , 185 , 255 , 75 , 20 , 74 , 0 , 187 , 11 , 101 , 0 , 46 , 48 , 129 , 255 , 22 , 239 , 210 , 255 , 77 , 236 , 129 , 255 , 111 , 77 , 204 , 255 , 61 , 72 , 97 , 255 , 199 , 217 , 251 , 255 , 42 , 215 , 204 , 0 , 133 , 145 , 201 , 255 , 57 , 230 , 146 , 1 , 235 , 100 , 198 , 0 , 146 , 73 , 35 , 254 , 108 , 198 , 20 , 255 , 182 , 79 , 210 , 255 , 82 , 103 , 136 , 0 , 246 , 108 , 176 , 0 , 34 , 17 , 60 , 255 , 19 , 74 , 114 , 254 , 168 , 170 , 78 , 255 , 157 , 239 , 20 , 255 , 149 , 41 , 168 , 0 , 58 , 121 , 28 , 0 , 79 , 179 , 134 , 255 , 231 , 121 , 135 , 255 , 174 , 209 , 98 , 255 , 243 , 122 , 190 , 0 , 171 , 166 , 205 , 0 , 212 , 116 , 48 , 0 , 29 , 108 , 66 , 255 , 162 , 222 , 182 , 1 , 14 , 119 , 21 , 0 , 213 , 39 , 249 , 255 , 254 , 223 , 228 , 255 , 183 , 165 , 198 , 0 , 133 , 190 , 48 , 0 , 124 , 208 , 109 , 255 , 119 , 175 , 85 , 255 , 9 , 209 , 121 , 1 , 48 , 171 , 189 , 255 , 195 , 71 , 134 , 1 , 136 , 219 , 51 , 255 , 182 , 91 , 141 , 254 , 49 , 159 , 72 , 0 , 35 , 118 , 245 , 255 , 112 , 186 , 227 , 255 , 59 , 137 , 31 , 0 , 137 , 44 , 163 , 0 , 114 , 103 , 60 , 254 , 8 , 213 , 150 , 0 , 162 , 10 , 113 , 255 , 194 , 104 , 72 , 0 , 220 , 131 , 116 , 255 , 178 , 79 , 92 , 0 , 203 , 250 , 213 , 254 , 93 , 193 , 189 , 255 , 130 , 255 , 34 , 254 , 212 , 188 , 151 , 0 , 136 , 17 , 20 , 255 , 20 , 101 , 83 , 255 , 212 , 206 , 166 , 0 , 229 , 238 , 73 , 255 , 151 , 74 , 3 , 255 , 168 , 87 , 215 , 0 , 155 , 188 , 133 , 255 , 166 , 129 , 73 , 0 , 240 , 79 , 133 , 255 , 178 , 211 , 81 , 255 , 203 , 72 , 163 , 254 , 193 , 168 , 165 , 0 , 14 , 164 , 199 , 254 , 30 , 255 , 204 , 0 , 65 , 72 , 91 , 1 , 166 , 74 , 102 , 255 , 200 , 42 , 0 , 255 , 194 , 113 , 227 , 255 , 66 , 23 , 208 , 0 , 229 , 216 , 100 , 255 , 24 , 239 , 26 , 0 , 10 , 233 , 62 , 255 , 123 , 10 , 178 , 1 , 26 , 36 , 174 , 255 , 119 , 219 , 199 , 1 , 45 , 163 , 190 , 0 , 16 , 168 , 42 , 0 , 166 , 57 , 198 , 255 , 28 , 26 , 26 , 0 , 126 , 165 , 231 , 0 , 251 , 108 , 100 , 255 , 61 , 229 , 121 , 255 , 58 , 118 , 138 , 0 , 76 , 207 , 17 , 0 , 13 , 34 , 112 , 254 , 89 , 16 , 168 , 0 , 37 , 208 , 105 , 255 , 35 , 201 , 215 , 255 , 40 , 106 , 101 , 254 , 6 , 239 , 114 , 0 , 40 , 103 , 226 , 254 , 246 , 127 , 110 , 255 , 63 , 167 , 58 , 0 , 132 , 240 , 142 , 0 , 5 , 158 , 88 , 255 , 129 , 73 , 158 , 255 , 94 , 89 , 146 , 0 , 230 , 54 , 146 , 0 , 8 , 45 , 173 , 0 , 79 , 169 , 1 , 0 , 115 , 186 , 247 , 0 , 84 , 64 , 131 , 0 , 67 , 224 , 253 , 255 , 207 , 189 , 64 , 0 , 154 , 28 , 81 , 1 , 45 , 184 , 54 , 255 , 87 , 212 , 224 , 255 , 0 , 96 , 73 , 255 , 129 , 33 , 235 , 1 , 52 , 66 , 80 , 255 , 251 , 174 , 155 , 255 , 4 , 179 , 37 , 0 , 234 , 164 , 93 , 254 , 93 , 175 , 253 , 0 , 198 , 69 , 87 , 255 , 224 , 106 , 46 , 0 , 99 , 29 , 210 , 0 , 62 , 188 , 114 , 255 , 44 , 234 , 8 , 0 , 169 , 175 , 247 , 255 , 23 , 109 , 137 , 255 , 229 , 182 , 39 , 0 , 192 , 165 , 94 , 254 , 245 , 101 , 217 , 0 , 191 , 88 , 96 , 0 , 196 , 94 , 99 , 255 , 106 , 238 , 11 , 254 , 53 , 126 , 243 , 0 , 94 , 1 , 101 , 255 , 46 , 147 , 2 , 0 , 201 , 124 , 124 , 255 , 141 , 12 , 218 , 0 , 13 , 166 , 157 , 1 , 48 , 251 , 237 , 255 , 155 , 250 , 124 , 255 , 106 , 148 , 146 , 255 , 182 , 13 , 202 , 0 , 28 , 61 , 167 , 0 , 217 , 152 , 8 , 254 , 220 , 130 , 45 , 255 , 200 , 230 , 255 , 1 , 55 , 65 , 87 , 255 , 93 , 191 , 97 , 254 , 114 , 251 , 14 , 0 , 32 , 105 , 92 , 1 , 26 , 207 , 141 , 0 , 24 , 207 , 13 , 254 , 21 , 50 , 48 , 255 , 186 , 148 , 116 , 255 , 211 , 43 , 225 , 0 , 37 , 34 , 162 , 254 , 164 , 210 , 42 , 255 , 68 , 23 , 96 , 255 , 182 , 214 , 8 , 255 , 245 , 117 , 137 , 255 , 66 , 195 , 50 , 0 , 75 , 12 , 83 , 254 , 80 , 140 , 164 , 0 , 9 , 165 , 36 , 1 , 228 , 110 , 227 , 0 , 241 , 17 , 90 , 1 , 25 , 52 , 212 , 0 , 6 , 223 , 12 , 255 , 139 , 243 , 57 , 0 , 12 , 113 , 75 , 1 , 246 , 183 , 191 , 255 , 213 , 191 , 69 , 255 , 230 , 15 , 142 , 0 , 1 , 195 , 196 , 255 , 138 , 171 , 47 , 255 , 64 , 63 , 106 , 1 , 16 , 169 , 214 , 255 , 207 , 174 , 56 , 1 , 88 , 73 , 133 , 255 , 182 , 133 , 140 , 0 , 177 , 14 , 25 , 255 , 147 , 184 , 53 , 255 , 10 , 227 , 161 , 255 , 120 , 216 , 244 , 255 , 73 , 77 , 233 , 0 , 157 , 238 , 139 , 1 , 59 , 65 , 233 , 0 , 70 , 251 , 216 , 1 , 41 , 184 , 153 , 255 , 32 , 203 , 112 , 0 , 146 , 147 , 253 , 0 , 87 , 101 , 109 , 1 , 44 , 82 , 133 , 255 , 244 , 150 , 53 , 255 , 94 , 152 , 232 , 255 , 59 , 93 , 39 , 255 , 88 , 147 , 220 , 255 , 78 , 81 , 13 , 1 , 32 , 47 , 252 , 255 , 160 , 19 , 114 , 255 , 93 , 107 , 39 , 255 , 118 , 16 , 211 , 1 , 185 , 119 , 209 , 255 , 227 , 219 , 127 , 254 , 88 , 105 , 236 , 255 , 162 , 110 , 23 , 255 , 36 , 166 , 110 , 255 , 91 , 236 , 221 , 2
. concat ( [ 187 , 164 , 227 , 1 , 160 , 25 , 5 , 0 , 12 , 78 , 195 , 1 , 43 , 197 , 225 , 0 , 48 , 142 , 41 , 254 , 196 , 155 , 60 , 255 , 223 , 199 , 18 , 1 , 145 , 136 , 156 , 0 , 252 , 117 , 169 , 254 , 145 , 226 , 238 , 0 , 239 , 23 , 107 , 0 , 109 , 181 , 188 , 255 , 230 , 112 , 49 , 254 , 73 , 170 , 237 , 255 , 231 , 183 , 227 , 255 , 80 , 220 , 20 , 0 , 194 , 107 , 127 , 1 , 127 , 205 , 101 , 0 , 46 , 52 , 197 , 1 , 210 , 171 , 36 , 255 , 88 , 3 , 90 , 255 , 56 , 151 , 141 , 0 , 96 , 187 , 255 , 255 , 42 , 78 , 200 , 0 , 254 , 70 , 70 , 1 , 244 , 125 , 168 , 0 , 204 , 68 , 138 , 1 , 124 , 215 , 70 , 0 , 102 , 66 , 200 , 254 , 17 , 52 , 228 , 0 , 117 , 220 , 143 , 254 , 203 , 248 , 123 , 0 , 56 , 18 , 174 , 255 , 186 , 151 , 164 , 255 , 51 , 232 , 208 , 1 , 160 , 228 , 43 , 255 , 249 , 29 , 25 , 1 , 68 , 190 , 63 , 0 , 34 , 174 , 40 , 215 , 152 , 47 , 138 , 66 , 205 , 101 , 239 , 35 , 145 , 68 , 55 , 113 , 47 , 59 , 77 , 236 , 207 , 251 , 192 , 181 , 188 , 219 , 137 , 129 , 165 , 219 , 181 , 233 , 56 , 181 , 72 , 243 , 91 , 194 , 86 , 57 , 25 , 208 , 5 , 182 , 241 , 17 , 241 , 89 , 155 , 79 , 25 , 175 , 164 , 130 , 63 , 146 , 24 , 129 , 109 , 218 , 213 , 94 , 28 , 171 , 66 , 2 , 3 , 163 , 152 , 170 , 7 , 216 , 190 , 111 , 112 , 69 , 1 , 91 , 131 , 18 , 140 , 178 , 228 , 78 , 190 , 133 , 49 , 36 , 226 , 180 , 255 , 213 , 195 , 125 , 12 , 85 , 111 , 137 , 123 , 242 , 116 , 93 , 190 , 114 , 177 , 150 , 22 , 59 , 254 , 177 , 222 , 128 , 53 , 18 , 199 , 37 , 167 , 6 , 220 , 155 , 148 , 38 , 105 , 207 , 116 , 241 , 155 , 193 , 210 , 74 , 241 , 158 , 193 , 105 , 155 , 228 , 227 , 37 , 79 , 56 , 134 , 71 , 190 , 239 , 181 , 213 , 140 , 139 , 198 , 157 , 193 , 15 , 101 , 156 , 172 , 119 , 204 , 161 , 12 , 36 , 117 , 2 , 43 , 89 , 111 , 44 , 233 , 45 , 131 , 228 , 166 , 110 , 170 , 132 , 116 , 74 , 212 , 251 , 65 , 189 , 220 , 169 , 176 , 92 , 181 , 83 , 17 , 131 , 218 , 136 , 249 , 118 , 171 , 223 , 102 , 238 , 82 , 81 , 62 , 152 , 16 , 50 , 180 , 45 , 109 , 198 , 49 , 168 , 63 , 33 , 251 , 152 , 200 , 39 , 3 , 176 , 228 , 14 , 239 , 190 , 199 , 127 , 89 , 191 , 194 , 143 , 168 , 61 , 243 , 11 , 224 , 198 , 37 , 167 , 10 , 147 , 71 , 145 , 167 , 213 , 111 , 130 , 3 , 224 , 81 , 99 , 202 , 6 , 112 , 110 , 14 , 10 , 103 , 41 , 41 , 20 , 252 , 47 , 210 , 70 , 133 , 10 , 183 , 39 , 38 , 201 , 38 , 92 , 56 , 33 , 27 , 46 , 237 , 42 , 196 , 90 , 252 , 109 , 44 , 77 , 223 , 179 , 149 , 157 , 19 , 13 , 56 , 83 , 222 , 99 , 175 , 139 , 84 , 115 , 10 , 101 , 168 , 178 , 119 , 60 , 187 , 10 , 106 , 118 , 230 , 174 , 237 , 71 , 46 , 201 , 194 , 129 , 59 , 53 , 130 , 20 , 133 , 44 , 114 , 146 , 100 , 3 , 241 , 76 , 161 , 232 , 191 , 162 , 1 , 48 , 66 , 188 , 75 , 102 , 26 , 168 , 145 , 151 , 248 , 208 , 112 , 139 , 75 , 194 , 48 , 190 , 84 , 6 , 163 , 81 , 108 , 199 , 24 , 82 , 239 , 214 , 25 , 232 , 146 , 209 , 16 , 169 , 101 , 85 , 36 , 6 , 153 , 214 , 42 , 32 , 113 , 87 , 133 , 53 , 14 , 244 , 184 , 209 , 187 , 50 , 112 , 160 , 106 , 16 , 200 , 208 , 210 , 184 , 22 , 193 , 164 , 25 , 83 , 171 , 65 , 81 , 8 , 108 , 55 , 30 , 153 , 235 , 142 , 223 , 76 , 119 , 72 , 39 , 168 , 72 , 155 , 225 , 181 , 188 , 176 , 52 , 99 , 90 , 201 , 197 , 179 , 12 , 28 , 57 , 203 , 138 , 65 , 227 , 74 , 170 , 216 , 78 , 115 , 227 , 99 , 119 , 79 , 202 , 156 , 91 , 163 , 184 , 178 , 214 , 243 , 111 , 46 , 104 , 252 , 178 , 239 , 93 , 238 , 130 , 143 , 116 , 96 , 47 , 23 , 67 , 111 , 99 , 165 , 120 , 114 , 171 , 240 , 161 , 20 , 120 , 200 , 132 , 236 , 57 , 100 , 26 , 8 , 2 , 199 , 140 , 40 , 30 , 99 , 35 , 250 , 255 , 190 , 144 , 233 , 189 , 130 , 222 , 235 , 108 , 80 , 164 , 21 , 121 , 198 , 178 , 247 , 163 , 249 , 190 , 43 , 83 , 114 , 227 , 242 , 120 , 113 , 198 , 156 , 97 , 38 , 234 , 206 , 62 , 39 , 202 , 7 , 194 , 192 , 33 , 199 , 184 , 134 , 209 , 30 , 235 , 224 , 205 , 214 , 125 , 218 , 234 , 120 , 209 , 110 , 238 , 127 , 79 , 125 , 245 , 186 , 111 , 23 , 114 , 170 , 103 , 240 , 6 , 166 , 152 , 200 , 162 , 197 , 125 , 99 , 10 , 174 , 13 , 249 , 190 , 4 , 152 , 63 , 17 , 27 , 71 , 28 , 19 , 53 , 11 , 113 , 27 , 132 , 125 , 4 , 35 , 245 , 119 , 219 , 40 , 147 , 36 , 199 , 64 , 123 , 171 , 202 , 50 , 188 , 190 , 201 , 21 , 10 , 190 , 158 , 60 , 76 , 13 , 16 , 156 , 196 , 103 , 29 , 67 , 182 , 66 , 62 , 203 , 190 , 212 , 197 , 76 , 42 , 126 , 101 , 252 , 156 , 41 , 127 , 89 , 236 , 250 , 214 , 58 , 171 , 111 , 203 , 95 , 23 , 88 , 71 , 74 , 140 , 25 , 68 , 108 , 8 , 201 , 188 , 243 , 103 , 230 , 9 , 106 , 59 , 167 , 202 , 132 , 133 , 174 , 103 , 187 , 43 , 248 , 148 , 254 , 114 , 243 , 110 , 60 , 241 , 54 , 29 , 95 , 58 , 245 , 79 , 165 , 209 , 130 , 230 , 173 , 127 , 82 , 14 , 81 , 31 , 108 , 62 , 43 , 140 , 104 , 5 , 155 , 107 , 189 , 65 , 251 , 171 , 217 , 131 , 31 , 121 , 33 , 126 , 19 , 25 , 205 , 224 , 91 , 133 , 59 , 140 , 1 , 189 , 241 , 36 , 255 , 248 , 37 , 195 , 1 , 96 , 220 , 55 , 0 , 183 , 76 , 62 , 255 , 195 , 66 , 61 , 0 , 50 , 76 , 164 , 1 , 225 , 164 , 76 , 255 , 76 , 61 , 163 , 255 , 117 , 62 , 31 , 0 , 81 , 145 , 64 , 255 , 118 , 65 , 14 , 0 , 162 , 115 , 214 , 255 , 6 , 138 , 46 , 0 , 124 , 230 , 244 , 255 , 10 , 138 , 143 , 0 , 52 , 26 , 194 , 0 , 184 , 244 , 76 , 0 , 129 , 143 , 41 , 1 , 190 , 244 , 19 , 255 , 123 , 170 , 122 , 255 , 98 , 129 , 68 , 0 , 121 , 213 , 147 , 0 , 86 , 101 , 30 , 255 , 161 , 103 , 155 , 0 , 140 , 89 , 67 , 255 , 239 , 229 , 190 , 1 , 67 , 11 , 181 , 0 , 198 , 240 , 137 , 254 , 238 , 69 , 188 , 255 , 67 , 151 , 238 , 0 , 19 , 42 , 108 , 255 , 229 , 85 , 113 , 1 , 50 , 68 , 135 , 255 , 17 , 106 , 9 , 0 , 50 , 103 , 1 , 255 , 80 , 1 , 168 , 1 , 35 , 152 , 30 , 255 , 16 , 168 , 185 , 1 , 56 , 89 , 232 , 255 , 101 , 210 , 252 , 0 , 41 , 250 , 71 , 0 , 204 , 170 , 79 , 255 , 14 , 46 , 239 , 255 , 80 , 77 , 239 , 0 , 189 , 214 , 75 , 255 , 17 , 141 , 249 , 0 , 38 , 80 , 76 , 255 , 190 , 85 , 117 , 0 , 86 , 228 , 170 , 0 , 156 , 216 , 208 , 1 , 195 , 207 , 164 , 255 , 150 , 66 , 76 , 255 , 175 , 225 , 16 , 255 , 141 , 80 , 98 , 1 , 76 , 219 , 242 , 0 , 198 , 162 , 114 , 0 , 46 , 218 , 152 , 0 , 155 , 43 , 241 , 254 , 155 , 160 , 104 , 255 , 51 , 187 , 165 , 0 , 2 , 17 , 175 , 0 , 66 , 84 , 160 , 1 , 247 , 58 , 30 , 0 , 35 , 65 , 53 , 254 , 69 , 236 , 191 , 0 , 45 , 134 , 245 , 1 , 163 , 123 , 221 , 0 , 32 , 110 , 20 , 255 , 52 , 23 , 165 , 0 , 186 , 214 , 71 , 0 , 233 , 176 , 96 , 0 , 242 , 239 , 54 , 1 , 57 , 89 , 138 , 0 , 83 , 0 , 84 , 255 , 136 , 160 , 100 , 0 , 92 , 142 , 120 , 254 , 104 , 1
, "i8" , ALLOC _NONE , Runtime . GLOBAL _BASE )
function runPostSets ( ) {
}
if ( ! awaitingMemoryInitializer ) runPostSets ( ) ;
var tempDoublePtr = Runtime . alignMemory ( allocate ( 12 , "i8" , ALLOC _STATIC ) , 8 ) ;
assert ( tempDoublePtr % 8 == 0 ) ;
function copyTempFloat ( ptr ) { // functions, because inlining this code increases code size too much
HEAP8 [ tempDoublePtr ] = HEAP8 [ ptr ] ;
HEAP8 [ tempDoublePtr + 1 ] = HEAP8 [ ptr + 1 ] ;
HEAP8 [ tempDoublePtr + 2 ] = HEAP8 [ ptr + 2 ] ;
HEAP8 [ tempDoublePtr + 3 ] = HEAP8 [ ptr + 3 ] ;
}
function copyTempDouble ( ptr ) {
HEAP8 [ tempDoublePtr ] = HEAP8 [ ptr ] ;
HEAP8 [ tempDoublePtr + 1 ] = HEAP8 [ ptr + 1 ] ;
HEAP8 [ tempDoublePtr + 2 ] = HEAP8 [ ptr + 2 ] ;
HEAP8 [ tempDoublePtr + 3 ] = HEAP8 [ ptr + 3 ] ;
HEAP8 [ tempDoublePtr + 4 ] = HEAP8 [ ptr + 4 ] ;
HEAP8 [ tempDoublePtr + 5 ] = HEAP8 [ ptr + 5 ] ;
HEAP8 [ tempDoublePtr + 6 ] = HEAP8 [ ptr + 6 ] ;
HEAP8 [ tempDoublePtr + 7 ] = HEAP8 [ ptr + 7 ] ;
}
Module [ "_memcpy" ] = _memcpy ;
Module [ "_memmove" ] = _memmove ; var _llvm _memmove _p0i8 _p0i8 _i32 = _memmove ;
var _llvm _memcpy _p0i8 _p0i8 _i32 = _memcpy ;
Module [ "_memset" ] = _memset ; var _llvm _memset _p0i8 _i32 = _memset ;
var _llvm _memset _p0i8 _i64 = _memset ;
function _llvm _lifetime _start ( ) { }
function _llvm _lifetime _end ( ) { }
function _malloc ( bytes ) {
/ * O v e r - a l l o c a t e t o m a k e s u r e i t i s b y t e - a l i g n e d b y 8 .
* This will leak memory , but this is only the dummy
* implementation ( replaced by dlmalloc normally ) so
* not an issue .
* /
var ptr = Runtime . dynamicAlloc ( bytes + 8 ) ;
return ( ptr + 8 ) & 0xFFFFFFF8 ;
}
Module [ "_malloc" ] = _malloc ;
function _free ( ) {
}
2015-02-11 12:49:17 -08:00
Module [ "_free" ] = _free ;
2015-01-14 11:24:45 -10:00
Module [ "_strlen" ] = _strlen ;
var Browser = { mainLoop : { scheduler : null , shouldPause : false , paused : false , queue : [ ] , pause : function ( ) {
Browser . mainLoop . shouldPause = true ;
} , resume : function ( ) {
if ( Browser . mainLoop . paused ) {
Browser . mainLoop . paused = false ;
Browser . mainLoop . scheduler ( ) ;
}
Browser . mainLoop . shouldPause = false ;
} , updateStatus : function ( ) {
if ( Module [ 'setStatus' ] ) {
var message = Module [ 'statusMessage' ] || 'Please wait...' ;
var remaining = Browser . mainLoop . remainingBlockers ;
var expected = Browser . mainLoop . expectedBlockers ;
if ( remaining ) {
if ( remaining < expected ) {
Module [ 'setStatus' ] ( message + ' (' + ( expected - remaining ) + '/' + expected + ')' ) ;
} else {
Module [ 'setStatus' ] ( message ) ;
}
} else {
Module [ 'setStatus' ] ( '' ) ;
}
}
} } , isFullScreen : false , pointerLock : false , moduleContextCreatedCallbacks : [ ] , workers : [ ] , init : function ( ) {
if ( Browser . initted ) return ;
Browser . initted = true ;
try {
new Blob ( ) ;
Browser . hasBlobConstructor = true ;
} catch ( e ) {
Browser . hasBlobConstructor = false ;
console . log ( "warning: no blob constructor, cannot create blobs with mimetypes" ) ;
}
Browser . BlobBuilder = typeof MozBlobBuilder != "undefined" ? MozBlobBuilder : ( typeof WebKitBlobBuilder != "undefined" ? WebKitBlobBuilder : ( ! Browser . hasBlobConstructor ? console . log ( "warning: no BlobBuilder" ) : null ) ) ;
Browser . URLObject = typeof window != "undefined" ? ( window . URL ? window . URL : window . webkitURL ) : console . log ( "warning: cannot create object URLs" ) ;
// Support for plugins that can process preloaded files. You can add more of these to
// your app by creating and appending to Module.preloadPlugins.
//
// Each plugin is asked if it can handle a file based on the file's name. If it can,
// it is given the file's raw data. When it is done, it calls a callback with the file's
// (possibly modified) data. For example, a plugin might decompress a file, or it
// might create some side data structure for use later (like an Image element, etc.).
function getMimetype ( name ) {
return {
'jpg' : 'image/jpeg' ,
'jpeg' : 'image/jpeg' ,
'png' : 'image/png' ,
'bmp' : 'image/bmp' ,
'ogg' : 'audio/ogg' ,
'wav' : 'audio/wav' ,
'mp3' : 'audio/mpeg'
} [ name . substr ( name . lastIndexOf ( '.' ) + 1 ) ] ;
}
if ( ! Module [ "preloadPlugins" ] ) Module [ "preloadPlugins" ] = [ ] ;
var imagePlugin = { } ;
imagePlugin [ 'canHandle' ] = function ( name ) {
return ! Module . noImageDecoding && /\.(jpg|jpeg|png|bmp)$/ . exec ( name ) ;
} ;
imagePlugin [ 'handle' ] = function ( byteArray , name , onload , onerror ) {
var b = null ;
if ( Browser . hasBlobConstructor ) {
try {
b = new Blob ( [ byteArray ] , { type : getMimetype ( name ) } ) ;
} catch ( e ) {
Runtime . warnOnce ( 'Blob constructor present but fails: ' + e + '; falling back to blob builder' ) ;
}
}
if ( ! b ) {
var bb = new Browser . BlobBuilder ( ) ;
bb . append ( ( new Uint8Array ( byteArray ) ) . buffer ) ; // we need to pass a buffer, and must copy the array to get the right data range
b = bb . getBlob ( ) ;
}
var url = Browser . URLObject . createObjectURL ( b ) ;
var img = new Image ( ) ;
img . onload = function ( ) {
assert ( img . complete , 'Image ' + name + ' could not be decoded' ) ;
var canvas = document . createElement ( 'canvas' ) ;
canvas . width = img . width ;
canvas . height = img . height ;
var ctx = canvas . getContext ( '2d' ) ;
ctx . drawImage ( img , 0 , 0 ) ;
Module [ "preloadedImages" ] [ name ] = canvas ;
Browser . URLObject . revokeObjectURL ( url ) ;
if ( onload ) onload ( byteArray ) ;
} ;
img . onerror = function ( event ) {
console . log ( 'Image ' + url + ' could not be decoded' ) ;
if ( onerror ) onerror ( ) ;
} ;
img . src = url ;
} ;
Module [ 'preloadPlugins' ] . push ( imagePlugin ) ;
var audioPlugin = { } ;
audioPlugin [ 'canHandle' ] = function ( name ) {
return ! Module . noAudioDecoding && name . substr ( - 4 ) in { '.ogg' : 1 , '.wav' : 1 , '.mp3' : 1 } ;
} ;
audioPlugin [ 'handle' ] = function ( byteArray , name , onload , onerror ) {
var done = false ;
function finish ( audio ) {
if ( done ) return ;
done = true ;
Module [ "preloadedAudios" ] [ name ] = audio ;
if ( onload ) onload ( byteArray ) ;
}
function fail ( ) {
if ( done ) return ;
done = true ;
Module [ "preloadedAudios" ] [ name ] = new Audio ( ) ; // empty shim
if ( onerror ) onerror ( ) ;
}
if ( Browser . hasBlobConstructor ) {
try {
var b = new Blob ( [ byteArray ] , { type : getMimetype ( name ) } ) ;
} catch ( e ) {
return fail ( ) ;
}
var url = Browser . URLObject . createObjectURL ( b ) ; // XXX we never revoke this!
var audio = new Audio ( ) ;
audio . addEventListener ( 'canplaythrough' , function ( ) { finish ( audio ) } , false ) ; // use addEventListener due to chromium bug 124926
audio . onerror = function ( event ) {
if ( done ) return ;
console . log ( 'warning: browser could not fully decode audio ' + name + ', trying slower base64 approach' ) ;
function encode64 ( data ) {
var BASE = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' ;
var PAD = '=' ;
var ret = '' ;
var leftchar = 0 ;
var leftbits = 0 ;
for ( var i = 0 ; i < data . length ; i ++ ) {
leftchar = ( leftchar << 8 ) | data [ i ] ;
leftbits += 8 ;
while ( leftbits >= 6 ) {
var curr = ( leftchar >> ( leftbits - 6 ) ) & 0x3f ;
leftbits -= 6 ;
ret += BASE [ curr ] ;
}
}
if ( leftbits == 2 ) {
ret += BASE [ ( leftchar & 3 ) << 4 ] ;
ret += PAD + PAD ;
} else if ( leftbits == 4 ) {
ret += BASE [ ( leftchar & 0xf ) << 2 ] ;
ret += PAD ;
}
return ret ;
}
audio . src = 'data:audio/x-' + name . substr ( - 3 ) + ';base64,' + encode64 ( byteArray ) ;
finish ( audio ) ; // we don't wait for confirmation this worked - but it's worth trying
} ;
audio . src = url ;
// workaround for chrome bug 124926 - we do not always get oncanplaythrough or onerror
Browser . safeSetTimeout ( function ( ) {
finish ( audio ) ; // try to use it even though it is not necessarily ready to play
} , 10000 ) ;
} else {
return fail ( ) ;
}
} ;
Module [ 'preloadPlugins' ] . push ( audioPlugin ) ;
// Canvas event setup
var canvas = Module [ 'canvas' ] ;
canvas . requestPointerLock = canvas [ 'requestPointerLock' ] ||
canvas [ 'mozRequestPointerLock' ] ||
canvas [ 'webkitRequestPointerLock' ] ;
canvas . exitPointerLock = document [ 'exitPointerLock' ] ||
document [ 'mozExitPointerLock' ] ||
document [ 'webkitExitPointerLock' ] ||
function ( ) { } ; // no-op if function does not exist
canvas . exitPointerLock = canvas . exitPointerLock . bind ( document ) ;
function pointerLockChange ( ) {
Browser . pointerLock = document [ 'pointerLockElement' ] === canvas ||
document [ 'mozPointerLockElement' ] === canvas ||
document [ 'webkitPointerLockElement' ] === canvas ;
}
document . addEventListener ( 'pointerlockchange' , pointerLockChange , false ) ;
document . addEventListener ( 'mozpointerlockchange' , pointerLockChange , false ) ;
document . addEventListener ( 'webkitpointerlockchange' , pointerLockChange , false ) ;
if ( Module [ 'elementPointerLock' ] ) {
canvas . addEventListener ( "click" , function ( ev ) {
if ( ! Browser . pointerLock && canvas . requestPointerLock ) {
canvas . requestPointerLock ( ) ;
ev . preventDefault ( ) ;
}
} , false ) ;
}
} , createContext : function ( canvas , useWebGL , setInModule ) {
var ctx ;
try {
if ( useWebGL ) {
ctx = canvas . getContext ( 'experimental-webgl' , {
alpha : false
} ) ;
} else {
ctx = canvas . getContext ( '2d' ) ;
}
if ( ! ctx ) throw ':(' ;
} catch ( e ) {
Module . print ( 'Could not create canvas - ' + e ) ;
return null ;
}
if ( useWebGL ) {
// Set the background of the WebGL canvas to black
canvas . style . backgroundColor = "black" ;
// Warn on context loss
canvas . addEventListener ( 'webglcontextlost' , function ( event ) {
alert ( 'WebGL context lost. You will need to reload the page.' ) ;
} , false ) ;
}
if ( setInModule ) {
Module . ctx = ctx ;
Module . useWebGL = useWebGL ;
Browser . moduleContextCreatedCallbacks . forEach ( function ( callback ) { callback ( ) } ) ;
Browser . init ( ) ;
}
return ctx ;
} , destroyContext : function ( canvas , useWebGL , setInModule ) { } , fullScreenHandlersInstalled : false , lockPointer : undefined , resizeCanvas : undefined , requestFullScreen : function ( lockPointer , resizeCanvas ) {
Browser . lockPointer = lockPointer ;
Browser . resizeCanvas = resizeCanvas ;
if ( typeof Browser . lockPointer === 'undefined' ) Browser . lockPointer = true ;
if ( typeof Browser . resizeCanvas === 'undefined' ) Browser . resizeCanvas = false ;
var canvas = Module [ 'canvas' ] ;
function fullScreenChange ( ) {
Browser . isFullScreen = false ;
if ( ( document [ 'webkitFullScreenElement' ] || document [ 'webkitFullscreenElement' ] ||
document [ 'mozFullScreenElement' ] || document [ 'mozFullscreenElement' ] ||
document [ 'fullScreenElement' ] || document [ 'fullscreenElement' ] ) === canvas ) {
canvas . cancelFullScreen = document [ 'cancelFullScreen' ] ||
document [ 'mozCancelFullScreen' ] ||
document [ 'webkitCancelFullScreen' ] ;
canvas . cancelFullScreen = canvas . cancelFullScreen . bind ( document ) ;
if ( Browser . lockPointer ) canvas . requestPointerLock ( ) ;
Browser . isFullScreen = true ;
if ( Browser . resizeCanvas ) Browser . setFullScreenCanvasSize ( ) ;
} else if ( Browser . resizeCanvas ) {
Browser . setWindowedCanvasSize ( ) ;
}
if ( Module [ 'onFullScreen' ] ) Module [ 'onFullScreen' ] ( Browser . isFullScreen ) ;
}
if ( ! Browser . fullScreenHandlersInstalled ) {
Browser . fullScreenHandlersInstalled = true ;
document . addEventListener ( 'fullscreenchange' , fullScreenChange , false ) ;
document . addEventListener ( 'mozfullscreenchange' , fullScreenChange , false ) ;
document . addEventListener ( 'webkitfullscreenchange' , fullScreenChange , false ) ;
}
canvas . requestFullScreen = canvas [ 'requestFullScreen' ] ||
canvas [ 'mozRequestFullScreen' ] ||
( canvas [ 'webkitRequestFullScreen' ] ? function ( ) { canvas [ 'webkitRequestFullScreen' ] ( Element [ 'ALLOW_KEYBOARD_INPUT' ] ) } : null ) ;
canvas . requestFullScreen ( ) ;
} , requestAnimationFrame : function ( func ) {
if ( ! window . requestAnimationFrame ) {
window . requestAnimationFrame = window [ 'requestAnimationFrame' ] ||
window [ 'mozRequestAnimationFrame' ] ||
window [ 'webkitRequestAnimationFrame' ] ||
window [ 'msRequestAnimationFrame' ] ||
window [ 'oRequestAnimationFrame' ] ||
window [ 'setTimeout' ] ;
}
window . requestAnimationFrame ( func ) ;
} , safeCallback : function ( func ) {
return function ( ) {
if ( ! ABORT ) return func . apply ( null , arguments ) ;
} ;
} , safeRequestAnimationFrame : function ( func ) {
return Browser . requestAnimationFrame ( function ( ) {
if ( ! ABORT ) func ( ) ;
} ) ;
} , safeSetTimeout : function ( func , timeout ) {
return setTimeout ( function ( ) {
if ( ! ABORT ) func ( ) ;
} , timeout ) ;
} , safeSetInterval : function ( func , timeout ) {
return setInterval ( function ( ) {
if ( ! ABORT ) func ( ) ;
} , timeout ) ;
} , getUserMedia : function ( func ) {
if ( ! window . getUserMedia ) {
window . getUserMedia = navigator [ 'getUserMedia' ] ||
navigator [ 'mozGetUserMedia' ] ;
}
window . getUserMedia ( func ) ;
} , getMovementX : function ( event ) {
return event [ 'movementX' ] ||
event [ 'mozMovementX' ] ||
event [ 'webkitMovementX' ] ||
0 ;
} , getMovementY : function ( event ) {
return event [ 'movementY' ] ||
event [ 'mozMovementY' ] ||
event [ 'webkitMovementY' ] ||
0 ;
} , mouseX : 0 , mouseY : 0 , mouseMovementX : 0 , mouseMovementY : 0 , calculateMouseEvent : function ( event ) { // event should be mousemove, mousedown or mouseup
if ( Browser . pointerLock ) {
// When the pointer is locked, calculate the coordinates
// based on the movement of the mouse.
// Workaround for Firefox bug 764498
if ( event . type != 'mousemove' &&
( 'mozMovementX' in event ) ) {
Browser . mouseMovementX = Browser . mouseMovementY = 0 ;
} else {
Browser . mouseMovementX = Browser . getMovementX ( event ) ;
Browser . mouseMovementY = Browser . getMovementY ( event ) ;
}
Browser . mouseX = SDL . mouseX + Browser . mouseMovementX ;
Browser . mouseY = SDL . mouseY + Browser . mouseMovementY ;
} else {
// Otherwise, calculate the movement based on the changes
// in the coordinates.
var rect = Module [ "canvas" ] . getBoundingClientRect ( ) ;
var x = event . pageX - ( window . scrollX + rect . left ) ;
var y = event . pageY - ( window . scrollY + rect . top ) ;
// the canvas might be CSS-scaled compared to its backbuffer;
// SDL-using content will want mouse coordinates in terms
// of backbuffer units.
var cw = Module [ "canvas" ] . width ;
var ch = Module [ "canvas" ] . height ;
x = x * ( cw / rect . width ) ;
y = y * ( ch / rect . height ) ;
Browser . mouseMovementX = x - Browser . mouseX ;
Browser . mouseMovementY = y - Browser . mouseY ;
Browser . mouseX = x ;
Browser . mouseY = y ;
}
} , xhrLoad : function ( url , onload , onerror ) {
var xhr = new XMLHttpRequest ( ) ;
xhr . open ( 'GET' , url , true ) ;
xhr . responseType = 'arraybuffer' ;
xhr . onload = function ( ) {
if ( xhr . status == 200 || ( xhr . status == 0 && xhr . response ) ) { // file URLs can return 0
onload ( xhr . response ) ;
} else {
onerror ( ) ;
}
} ;
xhr . onerror = onerror ;
xhr . send ( null ) ;
} , asyncLoad : function ( url , onload , onerror , noRunDep ) {
Browser . xhrLoad ( url , function ( arrayBuffer ) {
assert ( arrayBuffer , 'Loading data file "' + url + '" failed (no arrayBuffer).' ) ;
onload ( new Uint8Array ( arrayBuffer ) ) ;
if ( ! noRunDep ) removeRunDependency ( 'al ' + url ) ;
} , function ( event ) {
if ( onerror ) {
onerror ( ) ;
} else {
throw 'Loading data file "' + url + '" failed.' ;
}
} ) ;
if ( ! noRunDep ) addRunDependency ( 'al ' + url ) ;
} , resizeListeners : [ ] , updateResizeListeners : function ( ) {
var canvas = Module [ 'canvas' ] ;
Browser . resizeListeners . forEach ( function ( listener ) {
listener ( canvas . width , canvas . height ) ;
} ) ;
} , setCanvasSize : function ( width , height , noUpdates ) {
var canvas = Module [ 'canvas' ] ;
canvas . width = width ;
canvas . height = height ;
if ( ! noUpdates ) Browser . updateResizeListeners ( ) ;
} , windowedWidth : 0 , windowedHeight : 0 , setFullScreenCanvasSize : function ( ) {
var canvas = Module [ 'canvas' ] ;
this . windowedWidth = canvas . width ;
this . windowedHeight = canvas . height ;
canvas . width = screen . width ;
canvas . height = screen . height ;
var flags = HEAPU32 [ ( ( SDL . screen + Runtime . QUANTUM _SIZE * 0 ) >> 2 ) ] ;
flags = flags | 0x00800000 ; // set SDL_FULLSCREEN flag
HEAP32 [ ( ( SDL . screen + Runtime . QUANTUM _SIZE * 0 ) >> 2 ) ] = flags
Browser . updateResizeListeners ( ) ;
} , setWindowedCanvasSize : function ( ) {
var canvas = Module [ 'canvas' ] ;
canvas . width = this . windowedWidth ;
canvas . height = this . windowedHeight ;
var flags = HEAPU32 [ ( ( SDL . screen + Runtime . QUANTUM _SIZE * 0 ) >> 2 ) ] ;
flags = flags & ~ 0x00800000 ; // clear SDL_FULLSCREEN flag
HEAP32 [ ( ( SDL . screen + Runtime . QUANTUM _SIZE * 0 ) >> 2 ) ] = flags
Browser . updateResizeListeners ( ) ;
} } ;
Module [ "requestFullScreen" ] = function ( lockPointer , resizeCanvas ) { Browser . requestFullScreen ( lockPointer , resizeCanvas ) } ;
Module [ "requestAnimationFrame" ] = function ( func ) { Browser . requestAnimationFrame ( func ) } ;
Module [ "pauseMainLoop" ] = function ( ) { Browser . mainLoop . pause ( ) } ;
Module [ "resumeMainLoop" ] = function ( ) { Browser . mainLoop . resume ( ) } ;
Module [ "getUserMedia" ] = function ( ) { Browser . getUserMedia ( ) }
STACK _BASE = STACKTOP = Runtime . alignMemory ( STATICTOP ) ;
staticSealed = true ; // seal the static portion of memory
STACK _MAX = STACK _BASE + 5242880 ;
DYNAMIC _BASE = DYNAMICTOP = Runtime . alignMemory ( STACK _MAX ) ;
assert ( DYNAMIC _BASE < TOTAL _MEMORY ) ; // Stack must fit in TOTAL_MEMORY; allocations from here on may enlarge TOTAL_MEMORY
var ctlz _i8 = allocate ( [ 8 , 7 , 6 , 6 , 5 , 5 , 5 , 5 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ] , "i8" , ALLOC _DYNAMIC ) ;
var cttz _i8 = allocate ( [ 8 , 0 , 1 , 0 , 2 , 0 , 1 , 0 , 3 , 0 , 1 , 0 , 2 , 0 , 1 , 0 , 4 , 0 , 1 , 0 , 2 , 0 , 1 , 0 , 3 , 0 , 1 , 0 , 2 , 0 , 1 , 0 , 5 , 0 , 1 , 0 , 2 , 0 , 1 , 0 , 3 , 0 , 1 , 0 , 2 , 0 , 1 , 0 , 4 , 0 , 1 , 0 , 2 , 0 , 1 , 0 , 3 , 0 , 1 , 0 , 2 , 0 , 1 , 0 , 6 , 0 , 1 , 0 , 2 , 0 , 1 , 0 , 3 , 0 , 1 , 0 , 2 , 0 , 1 , 0 , 4 , 0 , 1 , 0 , 2 , 0 , 1 , 0 , 3 , 0 , 1 , 0 , 2 , 0 , 1 , 0 , 5 , 0 , 1 , 0 , 2 , 0 , 1 , 0 , 3 , 0 , 1 , 0 , 2 , 0 , 1 , 0 , 4 , 0 , 1 , 0 , 2 , 0 , 1 , 0 , 3 , 0 , 1 , 0 , 2 , 0 , 1 , 0 , 7 , 0 , 1 , 0 , 2 , 0 , 1 , 0 , 3 , 0 , 1 , 0 , 2 , 0 , 1 , 0 , 4 , 0 , 1 , 0 , 2 , 0 , 1 , 0 , 3 , 0 , 1 , 0 , 2 , 0 , 1 , 0 , 5 , 0 , 1 , 0 , 2 , 0 , 1 , 0 , 3 , 0 , 1 , 0 , 2 , 0 , 1 , 0 , 4 , 0 , 1 , 0 , 2 , 0 , 1 , 0 , 3 , 0 , 1 , 0 , 2 , 0 , 1 , 0 , 6 , 0 , 1 , 0 , 2 , 0 , 1 , 0 , 3 , 0 , 1 , 0 , 2 , 0 , 1 , 0 , 4 , 0 , 1 , 0 , 2 , 0 , 1 , 0 , 3 , 0 , 1 , 0 , 2 , 0 , 1 , 0 , 5 , 0 , 1 , 0 , 2 , 0 , 1 , 0 , 3 , 0 , 1 , 0 , 2 , 0 , 1 , 0 , 4 , 0 , 1 , 0 , 2 , 0 , 1 , 0 , 3 , 0 , 1 , 0 , 2 , 0 , 1 , 0 ] , "i8" , ALLOC _DYNAMIC ) ;
var Math _min = Math . min ;
function invoke _ii ( index , a1 ) {
try {
return Module [ "dynCall_ii" ] ( index , a1 ) ;
} catch ( e ) {
if ( typeof e !== 'number' && e !== 'longjmp' ) throw e ;
asm [ "setThrew" ] ( 1 , 0 ) ;
}
}
function invoke _v ( index ) {
try {
Module [ "dynCall_v" ] ( index ) ;
} catch ( e ) {
if ( typeof e !== 'number' && e !== 'longjmp' ) throw e ;
asm [ "setThrew" ] ( 1 , 0 ) ;
}
}
function invoke _iii ( index , a1 , a2 ) {
try {
return Module [ "dynCall_iii" ] ( index , a1 , a2 ) ;
} catch ( e ) {
if ( typeof e !== 'number' && e !== 'longjmp' ) throw e ;
asm [ "setThrew" ] ( 1 , 0 ) ;
}
}
function invoke _vi ( index , a1 ) {
try {
Module [ "dynCall_vi" ] ( index , a1 ) ;
} catch ( e ) {
if ( typeof e !== 'number' && e !== 'longjmp' ) throw e ;
asm [ "setThrew" ] ( 1 , 0 ) ;
}
}
function asmPrintInt ( x , y ) {
Module . print ( 'int ' + x + ',' + y ) ; // + ' ' + new Error().stack);
}
function asmPrintFloat ( x , y ) {
Module . print ( 'float ' + x + ',' + y ) ; // + ' ' + new Error().stack);
}
// EMSCRIPTEN_START_ASM
var asm = ( function ( global , env , buffer ) { "use asm" ; var a = new global . Int8Array ( buffer ) ; var b = new global . Int16Array ( buffer ) ; var c = new global . Int32Array ( buffer ) ; var d = new global . Uint8Array ( buffer ) ; var e = new global . Uint16Array ( buffer ) ; var f = new global . Uint32Array ( buffer ) ; var g = new global . Float32Array ( buffer ) ; var h = new global . Float64Array ( buffer ) ; var i = env . STACKTOP | 0 ; var j = env . STACK _MAX | 0 ; var k = env . tempDoublePtr | 0 ; var l = env . ABORT | 0 ; var m = env . cttz _i8 | 0 ; var n = env . ctlz _i8 | 0 ; var o = + env . NaN ; var p = + env . Infinity ; var q = 0 ; var r = 0 ; var s = 0 ; var t = 0 ; var u = 0 , v = 0 , w = 0 , x = 0 , y = 0.0 , z = 0 , A = 0 , B = 0 , C = 0.0 ; var D = 0 ; var E = 0 ; var F = 0 ; var G = 0 ; var H = 0 ; var I = 0 ; var J = 0 ; var K = 0 ; var L = 0 ; var M = 0 ; var N = global . Math . floor ; var O = global . Math . abs ; var P = global . Math . sqrt ; var Q = global . Math . pow ; var R = global . Math . cos ; var S = global . Math . sin ; var T = global . Math . tan ; var U = global . Math . acos ; var V = global . Math . asin ; var W = global . Math . atan ; var X = global . Math . atan2 ; var Y = global . Math . exp ; var Z = global . Math . log ; var _ = global . Math . ceil ; var $ = global . Math . imul ; var aa = env . abort ; var ab = env . assert ; var ac = env . asmPrintInt ; var ad = env . asmPrintFloat ; var ae = env . copyTempDouble ; var af = env . copyTempFloat ; var ag = env . min ; var ah = env . invoke _ii ; var ai = env . invoke _v ; var aj = env . invoke _iii ; var ak = env . invoke _vi ; var al = env . _llvm _lifetime _end ; var am = env . _malloc ; var an = env . _free ; var ao = env . _llvm _lifetime _start ;
2015-01-13 15:49:38 -10:00
// EMSCRIPTEN_START_FUNCS
2015-01-14 11:24:45 -10:00
function at ( a ) { a = a | 0 ; var b = 0 ; b = i ; i = i + a | 0 ; i = i + 7 >> 3 << 3 ; return b | 0 } function au ( ) { return i | 0 } function av ( a ) { a = a | 0 ; i = a } function aw ( a , b ) { a = a | 0 ; b = b | 0 ; if ( ( q | 0 ) == 0 ) { q = a ; r = b } } function ax ( a ) { a = a | 0 ; D = a } function ay ( a ) { a = a | 0 ; E = a } function az ( a ) { a = a | 0 ; F = a } function aA ( a ) { a = a | 0 ; G = a } function aB ( a ) { a = a | 0 ; H = a } function aC ( a ) { a = a | 0 ; I = a } function aD ( a ) { a = a | 0 ; J = a } function aE ( a ) { a = a | 0 ; K = a } function aF ( a ) { a = a | 0 ; L = a } function aG ( a ) { a = a | 0 ; M = a } function aH ( b , c ) { b = b | 0 ; c = c | 0 ; return ( ( ( ( a [ c + 1 | 0 ] ^ a [ b + 1 | 0 ] | a [ c ] ^ a [ b ] | a [ c + 2 | 0 ] ^ a [ b + 2 | 0 ] | a [ c + 3 | 0 ] ^ a [ b + 3 | 0 ] | a [ c + 4 | 0 ] ^ a [ b + 4 | 0 ] | a [ c + 5 | 0 ] ^ a [ b + 5 | 0 ] | a [ c + 6 | 0 ] ^ a [ b + 6 | 0 ] | a [ c + 7 | 0 ] ^ a [ b + 7 | 0 ] | a [ c + 8 | 0 ] ^ a [ b + 8 | 0 ] | a [ c + 9 | 0 ] ^ a [ b + 9 | 0 ] | a [ c + 10 | 0 ] ^ a [ b + 10 | 0 ] | a [ c + 11 | 0 ] ^ a [ b + 11 | 0 ] | a [ c + 12 | 0 ] ^ a [ b + 12 | 0 ] | a [ c + 13 | 0 ] ^ a [ b + 13 | 0 ] | a [ c + 14 | 0 ] ^ a [ b + 14 | 0 ] | a [ c + 15 | 0 ] ^ a [ b + 15 | 0 ] | a [ c + 16 | 0 ] ^ a [ b + 16 | 0 ] | a [ c + 17 | 0 ] ^ a [ b + 17 | 0 ] | a [ c + 18 | 0 ] ^ a [ b + 18 | 0 ] | a [ c + 19 | 0 ] ^ a [ b + 19 | 0 ] | a [ c + 20 | 0 ] ^ a [ b + 20 | 0 ] | a [ c + 21 | 0 ] ^ a [ b + 21 | 0 ] | a [ c + 22 | 0 ] ^ a [ b + 22 | 0 ] | a [ c + 23 | 0 ] ^ a [ b + 23 | 0 ] | a [ c + 24 | 0 ] ^ a [ b + 24 | 0 ] | a [ c + 25 | 0 ] ^ a [ b + 25 | 0 ] | a [ c + 26 | 0 ] ^ a [ b + 26 | 0 ] | a [ c + 27 | 0 ] ^ a [ b + 27 | 0 ] | a [ c + 28 | 0 ] ^ a [ b + 28 | 0 ] | a [ c + 29 | 0 ] ^ a [ b + 29 | 0 ] | a [ c + 30 | 0 ] ^ a [ b + 30 | 0 ] | a [ c + 31 | 0 ] ^ a [ b + 31 | 0 ] ) & 255 ) + 511 | 0 ) >>> 8 & 1 ) - 1 | 0 } function aI ( b , d , e , f ) { b = b | 0 ; d = d | 0 ; e = e | 0 ; f = f | 0 ; var g = 0 , h = 0 , j = 0 , k = 0 , l = 0 , m = 0 , n = 0 , o = 0 ; g = i ; i = i + 384 | 0 ; h = g + 152 | 0 ; j = g + 312 | 0 ; k = g + 376 | 0 ; l = i ; i = i + ( f + 64 | 0 ) | 0 ; i = i + 7 >> 3 << 3 ; c [ k >> 2 ] = 0 ; c [ k + 4 >> 2 ] = 0 ; m = j | 0 ; bb ( m | 0 , d | 0 , 32 ) ; a2 ( h , d ) ; d = g + 32 | 0 ; aR ( d , h + 80 | 0 ) ; n = g + 72 | 0 ; aP ( n , h | 0 , d ) ; o = g + 112 | 0 ; aP ( o , h + 40 | 0 , d ) ; aU ( j + 32 | 0 , o ) ; o = g | 0 ; aU ( o , n ) ; n = j + 63 | 0 ; j = a [ n ] ^ a [ o ] << 7 ; a [ n ] = j ; aK ( l , k , e , f , 0 , m ) ; bb ( b | 0 , l | 0 , 64 ) ; l = b + 63 | 0 ; a [ l ] = a [ l ] | j & - 128 ; i = g ; return } function aJ ( b , d , e , f ) { b = b | 0 ; d = d | 0 ; e = e | 0 ; f = f | 0 ; var g = 0 , h = 0 , j = 0 , k = 0 , l = 0 , m = 0 , n = 0 , o = 0 , p = 0 , q = 0 , r = 0 , s = 0 , t = 0 , u = 0 , v = 0 , w = 0 , x = 0 , y = 0 ; g = i ; i = i + 240 | 0 ; h = g | 0 ; j = g + 40 | 0 ; k = g + 80 | 0 ; l = g + 200 | 0 ; m = f + 64 | 0 ; n = i ; i = i + m | 0 ; i = i + 7 >> 3 << 3 ; o = i ; i = i + m | 0 ; i = i + 7 >> 3 << 3 ; p = h | 0 ; aO ( p , d ) ; d = j | 0 ; q = c [ p >> 2 ] | 0 ; p = c [ h + 4 >> 2 ] | 0 ; r = c [ h + 8 >> 2 ] | 0 ; s = c [ h + 12 >> 2 ] | 0 ; t = c [ h + 16 >> 2 ] | 0 ; u = c [ h + 20 >> 2 ] | 0 ; v = c [ h + 24 >> 2 ] | 0 ; w = c [ h + 28 >> 2 ] | 0 ; x = c [ h + 32 >> 2 ] | 0 ; y = c [ h + 36 >> 2 ] | 0 ; c [ d >> 2 ] = q - 1 ; c [ j + 4 >> 2 ] = p ; c [ j + 8 >> 2 ] = r ; c [ j + 12 >> 2 ] = s ; c [ j + 16 >> 2 ] = t ; c [ j + 20 >> 2 ] = u ; c [ j + 24 >> 2 ] = v ; c [ j + 28 >> 2 ] = w ; c [ j + 32 >> 2 ] = x ; c [ j + 36 >> 2 ] = y ; j = k | 0 ; c [ j >> 2 ] = q + 1 ; c [ k + 4 >> 2 ] = p ; c [ k + 8 >> 2 ] = r ; c [ k + 12 >> 2 ] = s ; c [ k + 16 >> 2 ] = t ; c [ k + 20 >> 2 ] = u ; c [ k + 24 >> 2 ] = v ; c [ k + 28 >> 2 ] = w ; c [ k + 32 >> 2 ] = x ; c [ k + 36 >> 2 ] = y ; y = g + 120 | 0 ; aR ( y , j ) ; j = g + 160 | 0 ; aP ( j , d , y ) ; y = l | 0 ; aU ( y , j ) ; j = b + 63 | 0 ; d = a [ j ] | 0 ; k = l + 31 | 0 ; a [ k ] = a [ k ] | d & - 128 ; a [ j ] = d & 127 ; bb ( n | 0 , b | 0 , 64 ) ; bb ( n + 64 | 0 , e | 0 , f ) ; f = a5 ( o , g + 232 | 0 , n , m , 0 , y ) | 0 ; i = g ; return f | 0 } function aK ( b , d , e , f , g , h ) { b = b | 0 ; d = d | 0 ; e = e | 0 ; f = f | 0 ; g = g | 0 ; h = h | 0 ; var j = 0 , k = 0 , l = 0 , m = 0 , n = 0 , o = 0 , p = 0 , q = 0 , r = 0 , s = 0 , t = 0 , u = 0 , v = 0 , w = 0 , x = 0 , y = 0 , z = 0 , A = 0 , B = 0 ; j = i ; i = i + 872 | 0 ; k = j | 0 ; l = j + 200 | 0 ; m = j + 232 | 0 ; n = j + 272 | 0 ; o = j + 312 | 0 ; p = j + 352 | 0 ; q = j + 648 | 0 ; r = j + 712 | 0 ; s = j + 552 | 0 ; bb ( s | 0 , h + 32 | 0 , 32 ) ; t = bf ( f , g , 64 , 0 ) | 0 ; c [ d >> 2 ] = t ; c [ d + 4 >> 2 ] = D ; bc ( b + 64 | 0 , e | 0 , f | 0 ) ; e = b + 32 | 0 ; bc ( e | 0 , h | 0 , 32 ) ; d = j + 584 | 0 ; u = bf ( f , g , 32 , 0 ) | 0 ; g = p | 0 ; f = p + 128 | 0 ; bb ( f | 0 , 31520 , 64 ) ; v = p + 192 | 0 ; c [ v >> 2 ] = 0 ; c [ v + 4 >> 2 ] = 0 ; w = u ; if ( ( w | 0 ) != 0 ) { u = f ; f = w ; w = e ; x = 0 ; while ( 1 ) { y = 128 - x | 0 ; z = y >>> 0 > f >>> 0 ? f : y ; bb ( p + x | 0 , w | 0 , z ) ; y = z + x | 0 ; if ( ( y | 0 ) == 128 ) { a9 ( g , u ) ; A = 0 } else { A = y } y = bf ( c [ v >> 2 ] | 0 , c [ v + 4 >> 2 ] | 0 , z , 0 ) | 0 ; c [ v >> 2 ] = y ; c [ v + 4 >> 2 ] = D ; if ( ( f | 0 ) == ( z | 0 ) ) { break } else { f = f - z | 0 ; w = w + z | 0 ; x = A } } } ba ( g , 0 , 0 , d , 8 ) ; bb ( e | 0 , s | 0 , 32 ) ; a7 ( d ) ; a2 ( r , d ) ; s = m | 0 ; aR ( s , r + 80 | 0 ) ; m = n | 0 ; aP ( m , r | 0 , s ) ; n = o | 0 ; aP ( n , r + 40 | 0 , s ) ; aU ( b , n ) ; n = l | 0 ; aU ( n , m ) ; m = b + 31 | 0 ; a [ m ] = a [ m ] ^ a [ n ] << 7 ; n = q | 0 ; q = k | 0 ; m = k + 128 | 0 ; bb ( m | 0 , 31520 , 64 ) ; l = k + 192 | 0 ; c [ l >> 2 ] = 0 ; c [ l + 4 >> 2 ] = 0 ; s = t ; if ( ( s | 0 ) == 0 ) { ba ( q , 0 , 0 , n , 8 ) ; a7 ( n ) ; a6 ( e , n , h , d ) ; i = j ; return 0 } t = m ; m = s ; s = b ; b = 0 ; while ( 1 ) { r = 128 - b | 0 ; o = r >>> 0 > m >>> 0 ? m : r ; bb ( k + b | 0 , s | 0 , o ) ; r = o + b | 0 ; if ( ( r | 0 ) == 128 ) { a9 ( q , t ) ; B = 0 } else { B = r } r = bf ( c [ l >> 2 ] | 0 , c [ l + 4 >> 2 ] | 0 , o , 0 ) | 0 ; c [ l >> 2 ] = r ; c [ l + 4 >> 2 ] = D ; if ( ( m | 0 ) == ( o | 0 ) ) { break } else { m = m - o | 0 ; s = s + o | 0 ; b = B } } ba ( q , 0 , 0 , n , 8 ) ; a7 ( n ) ; a6 ( e , n , h , d ) ; i = j ; return 0 } function aL ( b , e , f ) { b = b | 0 ; e = e | 0 ; f = f | 0 ; var g = 0 , h = 0 , j = 0 , k = 0 , l = 0 , m = 0 , n = 0 , o = 0 , p = 0 , q = 0 , r = 0 , s = 0 , t = 0 , u = 0 , v = 0 , w = 0 , x = 0 , y = 0 , z = 0 , A = 0 , B = 0 , C = 0 , E = 0 , F = 0 , G = 0 , H = 0 , I = 0 , J = 0 , K = 0 , L = 0 , M = 0 , N = 0 , O = 0 , P = 0 , Q = 0 , R = 0 , S = 0 , T = 0 , U = 0 , V = 0 , W = 0 , X = 0 , Y = 0 , Z = 0 , _ = 0 , aa = 0 , ab = 0 , ac = 0 , ad = 0 , ae = 0 , af = 0 , ag = 0 , ah = 0 , ai = 0 , aj = 0 , ak = 0 , al = 0 , am = 0 , an = 0 , ao = 0 , ap = 0 , aq = 0 , ar = 0 , as = 0 , at = 0 , au = 0 , av = 0 , aw = 0 , ax = 0 , ay = 0 , az = 0 , aA = 0 , aB = 0 , aC = 0 , aD = 0 , aE = 0 , aF = 0 , aG = 0 , aH = 0 , aI = 0 , aJ = 0 , aK = 0 , aL = 0 , aO = 0 , aP = 0 , aR = 0 , aS = 0 , aT = 0 , aU = 0 , aV = 0 , aW = 0 , aX = 0 , aY = 0 , aZ = 0 , a _ = 0 , a$ = 0 , a0 = 0 , a1 = 0 , a2 = 0 , a3 = 0 , a4 = 0 , a5 = 0 , a6 = 0 , a7 = 0 , a8 = 0 , a9 = 0 , ba = 0 , bc = 0 , be = 0 , bh = 0 , bi = 0 , bj = 0 , bk
2015-01-13 15:49:38 -10:00
// EMSCRIPTEN_END_FUNCS
2015-01-14 11:24:45 -10:00
var ap = [ bx , bx ] ; var aq = [ by , by ] ; var ar = [ bz , bz ] ; var as = [ bA , bA ] ; return { _curve25519 _verify : aJ , _crypto _sign _ed25519 _ref10 _ge _scalarmult _base : a2 , _strlen : be , _memmove : bc , _sph _sha512 _init : a8 , _curve25519 _donna : aL , _memset : bd , _memcpy : bb , _curve25519 _sign : aI , stackAlloc : at , stackSave : au , stackRestore : av , setThrew : aw , setTempRet0 : ax , setTempRet1 : ay , setTempRet2 : az , setTempRet3 : aA , setTempRet4 : aB , setTempRet5 : aC , setTempRet6 : aD , setTempRet7 : aE , setTempRet8 : aF , setTempRet9 : aG , dynCall _ii : bt , dynCall _v : bu , dynCall _iii : bv , dynCall _vi : bw } } )
2015-01-13 15:49:38 -10:00
// EMSCRIPTEN_END_ASM
2015-01-14 11:24:45 -10:00
( { "Math" : Math , "Int8Array" : Int8Array , "Int16Array" : Int16Array , "Int32Array" : Int32Array , "Uint8Array" : Uint8Array , "Uint16Array" : Uint16Array , "Uint32Array" : Uint32Array , "Float32Array" : Float32Array , "Float64Array" : Float64Array } , { "abort" : abort , "assert" : assert , "asmPrintInt" : asmPrintInt , "asmPrintFloat" : asmPrintFloat , "copyTempDouble" : copyTempDouble , "copyTempFloat" : copyTempFloat , "min" : Math _min , "invoke_ii" : invoke _ii , "invoke_v" : invoke _v , "invoke_iii" : invoke _iii , "invoke_vi" : invoke _vi , "_llvm_lifetime_end" : _llvm _lifetime _end , "_malloc" : _malloc , "_free" : _free , "_llvm_lifetime_start" : _llvm _lifetime _start , "STACKTOP" : STACKTOP , "STACK_MAX" : STACK _MAX , "tempDoublePtr" : tempDoublePtr , "ABORT" : ABORT , "cttz_i8" : cttz _i8 , "ctlz_i8" : ctlz _i8 , "NaN" : NaN , "Infinity" : Infinity } , buffer ) ;
var _curve25519 _verify = Module [ "_curve25519_verify" ] = asm [ "_curve25519_verify" ] ;
var _crypto _sign _ed25519 _ref10 _ge _scalarmult _base = Module [ "_crypto_sign_ed25519_ref10_ge_scalarmult_base" ] = asm [ "_crypto_sign_ed25519_ref10_ge_scalarmult_base" ] ;
var _strlen = Module [ "_strlen" ] = asm [ "_strlen" ] ;
var _memmove = Module [ "_memmove" ] = asm [ "_memmove" ] ;
var _sph _sha512 _init = Module [ "_sph_sha512_init" ] = asm [ "_sph_sha512_init" ] ;
var _curve25519 _donna = Module [ "_curve25519_donna" ] = asm [ "_curve25519_donna" ] ;
var _memset = Module [ "_memset" ] = asm [ "_memset" ] ;
var _memcpy = Module [ "_memcpy" ] = asm [ "_memcpy" ] ;
var _curve25519 _sign = Module [ "_curve25519_sign" ] = asm [ "_curve25519_sign" ] ;
var dynCall _ii = Module [ "dynCall_ii" ] = asm [ "dynCall_ii" ] ;
var dynCall _v = Module [ "dynCall_v" ] = asm [ "dynCall_v" ] ;
var dynCall _iii = Module [ "dynCall_iii" ] = asm [ "dynCall_iii" ] ;
var dynCall _vi = Module [ "dynCall_vi" ] = asm [ "dynCall_vi" ] ;
Runtime . stackAlloc = function ( size ) { return asm [ 'stackAlloc' ] ( size ) } ;
Runtime . stackSave = function ( ) { return asm [ 'stackSave' ] ( ) } ;
Runtime . stackRestore = function ( top ) { asm [ 'stackRestore' ] ( top ) } ;
// TODO: strip out parts of this we do not need
//======= begin closure i64 code =======
// Copyright 2009 The Closure Library Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/ * *
* @ fileoverview Defines a Long class for representing a 64 - bit two ' s - complement
* integer value , which faithfully simulates the behavior of a Java "long" . This
* implementation is derived from LongLib in GWT .
*
* /
var i64Math = ( function ( ) { // Emscripten wrapper
var goog = { math : { } } ;
/ * *
* Constructs a 64 - bit two ' s - complement integer , given its low and high 32 - bit
* values as * signed * integers . See the from * functions below for more
* convenient ways of constructing Longs .
*
* The internal representation of a long is the two given signed , 32 - bit values .
* We use 32 - bit pieces because these are the size of integers on which
* Javascript performs bit - operations . For operations like addition and
* multiplication , we split each number into 16 - bit pieces , which can easily be
* multiplied within Javascript ' s floating - point representation without overflow
* or change in sign .
*
* In the algorithms below , we frequently reduce the negative case to the
* positive case by negating the input ( s ) and then post - processing the result .
* Note that we must ALWAYS check specially whether those values are MIN _VALUE
* ( - 2 ^ 63 ) because - MIN _VALUE == MIN _VALUE ( since 2 ^ 63 cannot be represented as
* a positive number , it overflows back into a negative ) . Not handling this
* case would often result in infinite recursion .
*
* @ param { number } low The low ( signed ) 32 bits of the long .
* @ param { number } high The high ( signed ) 32 bits of the long .
* @ constructor
* /
goog . math . Long = function ( low , high ) {
/ * *
* @ type { number }
* @ private
* /
this . low _ = low | 0 ; // force into 32 signed bits.
/ * *
* @ type { number }
* @ private
* /
this . high _ = high | 0 ; // force into 32 signed bits.
} ;
// NOTE: Common constant values ZERO, ONE, NEG_ONE, etc. are defined below the
// from* methods on which they depend.
/ * *
* A cache of the Long representations of small integer values .
* @ type { ! Object }
* @ private
* /
goog . math . Long . IntCache _ = { } ;
/ * *
* Returns a Long representing the given ( 32 - bit ) integer value .
* @ param { number } value The 32 - bit integer in question .
* @ return { ! goog . math . Long } The corresponding Long value .
* /
goog . math . Long . fromInt = function ( value ) {
if ( - 128 <= value && value < 128 ) {
var cachedObj = goog . math . Long . IntCache _ [ value ] ;
if ( cachedObj ) {
return cachedObj ;
}
}
var obj = new goog . math . Long ( value | 0 , value < 0 ? - 1 : 0 ) ;
if ( - 128 <= value && value < 128 ) {
goog . math . Long . IntCache _ [ value ] = obj ;
}
return obj ;
} ;
/ * *
* Returns a Long representing the given value , provided that it is a finite
* number . Otherwise , zero is returned .
* @ param { number } value The number in question .
* @ return { ! goog . math . Long } The corresponding Long value .
* /
goog . math . Long . fromNumber = function ( value ) {
if ( isNaN ( value ) || ! isFinite ( value ) ) {
return goog . math . Long . ZERO ;
} else if ( value <= - goog . math . Long . TWO _PWR _63 _DBL _ ) {
return goog . math . Long . MIN _VALUE ;
} else if ( value + 1 >= goog . math . Long . TWO _PWR _63 _DBL _ ) {
return goog . math . Long . MAX _VALUE ;
} else if ( value < 0 ) {
return goog . math . Long . fromNumber ( - value ) . negate ( ) ;
} else {
return new goog . math . Long (
( value % goog . math . Long . TWO _PWR _32 _DBL _ ) | 0 ,
( value / goog . math . Long . TWO _PWR _32 _DBL _ ) | 0 ) ;
}
} ;
/ * *
* Returns a Long representing the 64 - bit integer that comes by concatenating
* the given high and low bits . Each is assumed to use 32 bits .
* @ param { number } lowBits The low 32 - bits .
* @ param { number } highBits The high 32 - bits .
* @ return { ! goog . math . Long } The corresponding Long value .
* /
goog . math . Long . fromBits = function ( lowBits , highBits ) {
return new goog . math . Long ( lowBits , highBits ) ;
} ;
/ * *
* Returns a Long representation of the given string , written using the given
* radix .
* @ param { string } str The textual representation of the Long .
* @ param { number = } opt _radix The radix in which the text is written .
* @ return { ! goog . math . Long } The corresponding Long value .
* /
goog . math . Long . fromString = function ( str , opt _radix ) {
if ( str . length == 0 ) {
throw Error ( 'number format error: empty string' ) ;
}
var radix = opt _radix || 10 ;
if ( radix < 2 || 36 < radix ) {
throw Error ( 'radix out of range: ' + radix ) ;
}
if ( str . charAt ( 0 ) == '-' ) {
return goog . math . Long . fromString ( str . substring ( 1 ) , radix ) . negate ( ) ;
} else if ( str . indexOf ( '-' ) >= 0 ) {
throw Error ( 'number format error: interior "-" character: ' + str ) ;
}
// Do several (8) digits each time through the loop, so as to
// minimize the calls to the very expensive emulated div.
var radixToPower = goog . math . Long . fromNumber ( Math . pow ( radix , 8 ) ) ;
var result = goog . math . Long . ZERO ;
for ( var i = 0 ; i < str . length ; i += 8 ) {
var size = Math . min ( 8 , str . length - i ) ;
var value = parseInt ( str . substring ( i , i + size ) , radix ) ;
if ( size < 8 ) {
var power = goog . math . Long . fromNumber ( Math . pow ( radix , size ) ) ;
result = result . multiply ( power ) . add ( goog . math . Long . fromNumber ( value ) ) ;
} else {
result = result . multiply ( radixToPower ) ;
result = result . add ( goog . math . Long . fromNumber ( value ) ) ;
}
}
return result ;
} ;
// NOTE: the compiler should inline these constant values below and then remove
// these variables, so there should be no runtime penalty for these.
/ * *
* Number used repeated below in calculations . This must appear before the
* first call to any from * function below .
* @ type { number }
* @ private
* /
goog . math . Long . TWO _PWR _16 _DBL _ = 1 << 16 ;
/ * *
* @ type { number }
* @ private
* /
goog . math . Long . TWO _PWR _24 _DBL _ = 1 << 24 ;
/ * *
* @ type { number }
* @ private
* /
goog . math . Long . TWO _PWR _32 _DBL _ =
goog . math . Long . TWO _PWR _16 _DBL _ * goog . math . Long . TWO _PWR _16 _DBL _ ;
/ * *
* @ type { number }
* @ private
* /
goog . math . Long . TWO _PWR _31 _DBL _ =
goog . math . Long . TWO _PWR _32 _DBL _ / 2 ;
/ * *
* @ type { number }
* @ private
* /
goog . math . Long . TWO _PWR _48 _DBL _ =
goog . math . Long . TWO _PWR _32 _DBL _ * goog . math . Long . TWO _PWR _16 _DBL _ ;
/ * *
* @ type { number }
* @ private
* /
goog . math . Long . TWO _PWR _64 _DBL _ =
goog . math . Long . TWO _PWR _32 _DBL _ * goog . math . Long . TWO _PWR _32 _DBL _ ;
/ * *
* @ type { number }
* @ private
* /
goog . math . Long . TWO _PWR _63 _DBL _ =
goog . math . Long . TWO _PWR _64 _DBL _ / 2 ;
/** @type {!goog.math.Long} */
goog . math . Long . ZERO = goog . math . Long . fromInt ( 0 ) ;
/** @type {!goog.math.Long} */
goog . math . Long . ONE = goog . math . Long . fromInt ( 1 ) ;
/** @type {!goog.math.Long} */
goog . math . Long . NEG _ONE = goog . math . Long . fromInt ( - 1 ) ;
/** @type {!goog.math.Long} */
goog . math . Long . MAX _VALUE =
goog . math . Long . fromBits ( 0xFFFFFFFF | 0 , 0x7FFFFFFF | 0 ) ;
/** @type {!goog.math.Long} */
goog . math . Long . MIN _VALUE = goog . math . Long . fromBits ( 0 , 0x80000000 | 0 ) ;
/ * *
* @ type { ! goog . math . Long }
* @ private
* /
goog . math . Long . TWO _PWR _24 _ = goog . math . Long . fromInt ( 1 << 24 ) ;
/** @return {number} The value, assuming it is a 32-bit integer. */
goog . math . Long . prototype . toInt = function ( ) {
return this . low _ ;
} ;
/** @return {number} The closest floating-point representation to this value. */
goog . math . Long . prototype . toNumber = function ( ) {
return this . high _ * goog . math . Long . TWO _PWR _32 _DBL _ +
this . getLowBitsUnsigned ( ) ;
} ;
/ * *
* @ param { number = } opt _radix The radix in which the text should be written .
* @ return { string } The textual representation of this value .
* /
goog . math . Long . prototype . toString = function ( opt _radix ) {
var radix = opt _radix || 10 ;
if ( radix < 2 || 36 < radix ) {
throw Error ( 'radix out of range: ' + radix ) ;
}
if ( this . isZero ( ) ) {
return '0' ;
}
if ( this . isNegative ( ) ) {
if ( this . equals ( goog . math . Long . MIN _VALUE ) ) {
// We need to change the Long value before it can be negated, so we remove
// the bottom-most digit in this base and then recurse to do the rest.
var radixLong = goog . math . Long . fromNumber ( radix ) ;
var div = this . div ( radixLong ) ;
var rem = div . multiply ( radixLong ) . subtract ( this ) ;
return div . toString ( radix ) + rem . toInt ( ) . toString ( radix ) ;
} else {
return '-' + this . negate ( ) . toString ( radix ) ;
}
}
// Do several (6) digits each time through the loop, so as to
// minimize the calls to the very expensive emulated div.
var radixToPower = goog . math . Long . fromNumber ( Math . pow ( radix , 6 ) ) ;
var rem = this ;
var result = '' ;
while ( true ) {
var remDiv = rem . div ( radixToPower ) ;
var intval = rem . subtract ( remDiv . multiply ( radixToPower ) ) . toInt ( ) ;
var digits = intval . toString ( radix ) ;
rem = remDiv ;
if ( rem . isZero ( ) ) {
return digits + result ;
} else {
while ( digits . length < 6 ) {
digits = '0' + digits ;
}
result = '' + digits + result ;
}
}
} ;
/** @return {number} The high 32-bits as a signed value. */
goog . math . Long . prototype . getHighBits = function ( ) {
return this . high _ ;
} ;
/** @return {number} The low 32-bits as a signed value. */
goog . math . Long . prototype . getLowBits = function ( ) {
return this . low _ ;
} ;
/** @return {number} The low 32-bits as an unsigned value. */
goog . math . Long . prototype . getLowBitsUnsigned = function ( ) {
return ( this . low _ >= 0 ) ?
this . low _ : goog . math . Long . TWO _PWR _32 _DBL _ + this . low _ ;
} ;
/ * *
* @ return { number } Returns the number of bits needed to represent the absolute
* value of this Long .
* /
goog . math . Long . prototype . getNumBitsAbs = function ( ) {
if ( this . isNegative ( ) ) {
if ( this . equals ( goog . math . Long . MIN _VALUE ) ) {
return 64 ;
} else {
return this . negate ( ) . getNumBitsAbs ( ) ;
}
} else {
var val = this . high _ != 0 ? this . high _ : this . low _ ;
for ( var bit = 31 ; bit > 0 ; bit -- ) {
if ( ( val & ( 1 << bit ) ) != 0 ) {
break ;
}
}
return this . high _ != 0 ? bit + 33 : bit + 1 ;
}
} ;
/** @return {boolean} Whether this value is zero. */
goog . math . Long . prototype . isZero = function ( ) {
return this . high _ == 0 && this . low _ == 0 ;
} ;
/** @return {boolean} Whether this value is negative. */
goog . math . Long . prototype . isNegative = function ( ) {
return this . high _ < 0 ;
} ;
/** @return {boolean} Whether this value is odd. */
goog . math . Long . prototype . isOdd = function ( ) {
return ( this . low _ & 1 ) == 1 ;
} ;
/ * *
* @ param { goog . math . Long } other Long to compare against .
* @ return { boolean } Whether this Long equals the other .
* /
goog . math . Long . prototype . equals = function ( other ) {
return ( this . high _ == other . high _ ) && ( this . low _ == other . low _ ) ;
} ;
/ * *
* @ param { goog . math . Long } other Long to compare against .
* @ return { boolean } Whether this Long does not equal the other .
* /
goog . math . Long . prototype . notEquals = function ( other ) {
return ( this . high _ != other . high _ ) || ( this . low _ != other . low _ ) ;
} ;
/ * *
* @ param { goog . math . Long } other Long to compare against .
* @ return { boolean } Whether this Long is less than the other .
* /
goog . math . Long . prototype . lessThan = function ( other ) {
return this . compare ( other ) < 0 ;
} ;
/ * *
* @ param { goog . math . Long } other Long to compare against .
* @ return { boolean } Whether this Long is less than or equal to the other .
* /
goog . math . Long . prototype . lessThanOrEqual = function ( other ) {
return this . compare ( other ) <= 0 ;
} ;
/ * *
* @ param { goog . math . Long } other Long to compare against .
* @ return { boolean } Whether this Long is greater than the other .
* /
goog . math . Long . prototype . greaterThan = function ( other ) {
return this . compare ( other ) > 0 ;
} ;
/ * *
* @ param { goog . math . Long } other Long to compare against .
* @ return { boolean } Whether this Long is greater than or equal to the other .
* /
goog . math . Long . prototype . greaterThanOrEqual = function ( other ) {
return this . compare ( other ) >= 0 ;
} ;
/ * *
* Compares this Long with the given one .
* @ param { goog . math . Long } other Long to compare against .
* @ return { number } 0 if they are the same , 1 if the this is greater , and - 1
* if the given one is greater .
* /
goog . math . Long . prototype . compare = function ( other ) {
if ( this . equals ( other ) ) {
return 0 ;
}
var thisNeg = this . isNegative ( ) ;
var otherNeg = other . isNegative ( ) ;
if ( thisNeg && ! otherNeg ) {
return - 1 ;
}
if ( ! thisNeg && otherNeg ) {
return 1 ;
}
// at this point, the signs are the same, so subtraction will not overflow
if ( this . subtract ( other ) . isNegative ( ) ) {
return - 1 ;
} else {
return 1 ;
}
} ;
/** @return {!goog.math.Long} The negation of this value. */
goog . math . Long . prototype . negate = function ( ) {
if ( this . equals ( goog . math . Long . MIN _VALUE ) ) {
return goog . math . Long . MIN _VALUE ;
} else {
return this . not ( ) . add ( goog . math . Long . ONE ) ;
}
} ;
/ * *
* Returns the sum of this and the given Long .
* @ param { goog . math . Long } other Long to add to this one .
* @ return { ! goog . math . Long } The sum of this and the given Long .
* /
goog . math . Long . prototype . add = function ( other ) {
// Divide each number into 4 chunks of 16 bits, and then sum the chunks.
var a48 = this . high _ >>> 16 ;
var a32 = this . high _ & 0xFFFF ;
var a16 = this . low _ >>> 16 ;
var a00 = this . low _ & 0xFFFF ;
var b48 = other . high _ >>> 16 ;
var b32 = other . high _ & 0xFFFF ;
var b16 = other . low _ >>> 16 ;
var b00 = other . low _ & 0xFFFF ;
var c48 = 0 , c32 = 0 , c16 = 0 , c00 = 0 ;
c00 += a00 + b00 ;
c16 += c00 >>> 16 ;
c00 &= 0xFFFF ;
c16 += a16 + b16 ;
c32 += c16 >>> 16 ;
c16 &= 0xFFFF ;
c32 += a32 + b32 ;
c48 += c32 >>> 16 ;
c32 &= 0xFFFF ;
c48 += a48 + b48 ;
c48 &= 0xFFFF ;
return goog . math . Long . fromBits ( ( c16 << 16 ) | c00 , ( c48 << 16 ) | c32 ) ;
} ;
/ * *
* Returns the difference of this and the given Long .
* @ param { goog . math . Long } other Long to subtract from this .
* @ return { ! goog . math . Long } The difference of this and the given Long .
* /
goog . math . Long . prototype . subtract = function ( other ) {
return this . add ( other . negate ( ) ) ;
} ;
/ * *
* Returns the product of this and the given long .
* @ param { goog . math . Long } other Long to multiply with this .
* @ return { ! goog . math . Long } The product of this and the other .
* /
goog . math . Long . prototype . multiply = function ( other ) {
if ( this . isZero ( ) ) {
return goog . math . Long . ZERO ;
} else if ( other . isZero ( ) ) {
return goog . math . Long . ZERO ;
}
if ( this . equals ( goog . math . Long . MIN _VALUE ) ) {
return other . isOdd ( ) ? goog . math . Long . MIN _VALUE : goog . math . Long . ZERO ;
} else if ( other . equals ( goog . math . Long . MIN _VALUE ) ) {
return this . isOdd ( ) ? goog . math . Long . MIN _VALUE : goog . math . Long . ZERO ;
}
if ( this . isNegative ( ) ) {
if ( other . isNegative ( ) ) {
return this . negate ( ) . multiply ( other . negate ( ) ) ;
} else {
return this . negate ( ) . multiply ( other ) . negate ( ) ;
}
} else if ( other . isNegative ( ) ) {
return this . multiply ( other . negate ( ) ) . negate ( ) ;
}
// If both longs are small, use float multiplication
if ( this . lessThan ( goog . math . Long . TWO _PWR _24 _ ) &&
other . lessThan ( goog . math . Long . TWO _PWR _24 _ ) ) {
return goog . math . Long . fromNumber ( this . toNumber ( ) * other . toNumber ( ) ) ;
}
// Divide each long into 4 chunks of 16 bits, and then add up 4x4 products.
// We can skip products that would overflow.
var a48 = this . high _ >>> 16 ;
var a32 = this . high _ & 0xFFFF ;
var a16 = this . low _ >>> 16 ;
var a00 = this . low _ & 0xFFFF ;
var b48 = other . high _ >>> 16 ;
var b32 = other . high _ & 0xFFFF ;
var b16 = other . low _ >>> 16 ;
var b00 = other . low _ & 0xFFFF ;
var c48 = 0 , c32 = 0 , c16 = 0 , c00 = 0 ;
c00 += a00 * b00 ;
c16 += c00 >>> 16 ;
c00 &= 0xFFFF ;
c16 += a16 * b00 ;
c32 += c16 >>> 16 ;
c16 &= 0xFFFF ;
c16 += a00 * b16 ;
c32 += c16 >>> 16 ;
c16 &= 0xFFFF ;
c32 += a32 * b00 ;
c48 += c32 >>> 16 ;
c32 &= 0xFFFF ;
c32 += a16 * b16 ;
c48 += c32 >>> 16 ;
c32 &= 0xFFFF ;
c32 += a00 * b32 ;
c48 += c32 >>> 16 ;
c32 &= 0xFFFF ;
c48 += a48 * b00 + a32 * b16 + a16 * b32 + a00 * b48 ;
c48 &= 0xFFFF ;
return goog . math . Long . fromBits ( ( c16 << 16 ) | c00 , ( c48 << 16 ) | c32 ) ;
} ;
/ * *
* Returns this Long divided by the given one .
* @ param { goog . math . Long } other Long by which to divide .
* @ return { ! goog . math . Long } This Long divided by the given one .
* /
goog . math . Long . prototype . div = function ( other ) {
if ( other . isZero ( ) ) {
throw Error ( 'division by zero' ) ;
} else if ( this . isZero ( ) ) {
return goog . math . Long . ZERO ;
}
if ( this . equals ( goog . math . Long . MIN _VALUE ) ) {
if ( other . equals ( goog . math . Long . ONE ) ||
other . equals ( goog . math . Long . NEG _ONE ) ) {
return goog . math . Long . MIN _VALUE ; // recall that -MIN_VALUE == MIN_VALUE
} else if ( other . equals ( goog . math . Long . MIN _VALUE ) ) {
return goog . math . Long . ONE ;
} else {
// At this point, we have |other| >= 2, so |this/other| < |MIN_VALUE|.
var halfThis = this . shiftRight ( 1 ) ;
var approx = halfThis . div ( other ) . shiftLeft ( 1 ) ;
if ( approx . equals ( goog . math . Long . ZERO ) ) {
return other . isNegative ( ) ? goog . math . Long . ONE : goog . math . Long . NEG _ONE ;
} else {
var rem = this . subtract ( other . multiply ( approx ) ) ;
var result = approx . add ( rem . div ( other ) ) ;
return result ;
}
}
} else if ( other . equals ( goog . math . Long . MIN _VALUE ) ) {
return goog . math . Long . ZERO ;
}
if ( this . isNegative ( ) ) {
if ( other . isNegative ( ) ) {
return this . negate ( ) . div ( other . negate ( ) ) ;
} else {
return this . negate ( ) . div ( other ) . negate ( ) ;
}
} else if ( other . isNegative ( ) ) {
return this . div ( other . negate ( ) ) . negate ( ) ;
}
// Repeat the following until the remainder is less than other: find a
// floating-point that approximates remainder / other *from below*, add this
// into the result, and subtract it from the remainder. It is critical that
// the approximate value is less than or equal to the real value so that the
// remainder never becomes negative.
var res = goog . math . Long . ZERO ;
var rem = this ;
while ( rem . greaterThanOrEqual ( other ) ) {
// Approximate the result of division. This may be a little greater or
// smaller than the actual value.
var approx = Math . max ( 1 , Math . floor ( rem . toNumber ( ) / other . toNumber ( ) ) ) ;
// We will tweak the approximate result by changing it in the 48-th digit or
// the smallest non-fractional digit, whichever is larger.
var log2 = Math . ceil ( Math . log ( approx ) / Math . LN2 ) ;
var delta = ( log2 <= 48 ) ? 1 : Math . pow ( 2 , log2 - 48 ) ;
// Decrease the approximation until it is smaller than the remainder. Note
// that if it is too large, the product overflows and is negative.
var approxRes = goog . math . Long . fromNumber ( approx ) ;
var approxRem = approxRes . multiply ( other ) ;
while ( approxRem . isNegative ( ) || approxRem . greaterThan ( rem ) ) {
approx -= delta ;
approxRes = goog . math . Long . fromNumber ( approx ) ;
approxRem = approxRes . multiply ( other ) ;
}
// We know the answer can't be zero... and actually, zero would cause
// infinite recursion since we would make no progress.
if ( approxRes . isZero ( ) ) {
approxRes = goog . math . Long . ONE ;
}
res = res . add ( approxRes ) ;
rem = rem . subtract ( approxRem ) ;
}
return res ;
} ;
/ * *
* Returns this Long modulo the given one .
* @ param { goog . math . Long } other Long by which to mod .
* @ return { ! goog . math . Long } This Long modulo the given one .
* /
goog . math . Long . prototype . modulo = function ( other ) {
return this . subtract ( this . div ( other ) . multiply ( other ) ) ;
} ;
/** @return {!goog.math.Long} The bitwise-NOT of this value. */
goog . math . Long . prototype . not = function ( ) {
return goog . math . Long . fromBits ( ~ this . low _ , ~ this . high _ ) ;
} ;
/ * *
* Returns the bitwise - AND of this Long and the given one .
* @ param { goog . math . Long } other The Long with which to AND .
* @ return { ! goog . math . Long } The bitwise - AND of this and the other .
* /
goog . math . Long . prototype . and = function ( other ) {
return goog . math . Long . fromBits ( this . low _ & other . low _ ,
this . high _ & other . high _ ) ;
} ;
/ * *
* Returns the bitwise - OR of this Long and the given one .
* @ param { goog . math . Long } other The Long with which to OR .
* @ return { ! goog . math . Long } The bitwise - OR of this and the other .
* /
goog . math . Long . prototype . or = function ( other ) {
return goog . math . Long . fromBits ( this . low _ | other . low _ ,
this . high _ | other . high _ ) ;
} ;
/ * *
* Returns the bitwise - XOR of this Long and the given one .
* @ param { goog . math . Long } other The Long with which to XOR .
* @ return { ! goog . math . Long } The bitwise - XOR of this and the other .
* /
goog . math . Long . prototype . xor = function ( other ) {
return goog . math . Long . fromBits ( this . low _ ^ other . low _ ,
this . high _ ^ other . high _ ) ;
} ;
/ * *
* Returns this Long with bits shifted to the left by the given amount .
* @ param { number } numBits The number of bits by which to shift .
* @ return { ! goog . math . Long } This shifted to the left by the given amount .
* /
goog . math . Long . prototype . shiftLeft = function ( numBits ) {
numBits &= 63 ;
if ( numBits == 0 ) {
return this ;
} else {
var low = this . low _ ;
if ( numBits < 32 ) {
var high = this . high _ ;
return goog . math . Long . fromBits (
low << numBits ,
( high << numBits ) | ( low >>> ( 32 - numBits ) ) ) ;
} else {
return goog . math . Long . fromBits ( 0 , low << ( numBits - 32 ) ) ;
}
}
} ;
/ * *
* Returns this Long with bits shifted to the right by the given amount .
* @ param { number } numBits The number of bits by which to shift .
* @ return { ! goog . math . Long } This shifted to the right by the given amount .
* /
goog . math . Long . prototype . shiftRight = function ( numBits ) {
numBits &= 63 ;
if ( numBits == 0 ) {
return this ;
} else {
var high = this . high _ ;
if ( numBits < 32 ) {
var low = this . low _ ;
return goog . math . Long . fromBits (
( low >>> numBits ) | ( high << ( 32 - numBits ) ) ,
high >> numBits ) ;
} else {
return goog . math . Long . fromBits (
high >> ( numBits - 32 ) ,
high >= 0 ? 0 : - 1 ) ;
}
}
} ;
/ * *
* Returns this Long with bits shifted to the right by the given amount , with
* the new top bits matching the current sign bit .
* @ param { number } numBits The number of bits by which to shift .
* @ return { ! goog . math . Long } This shifted to the right by the given amount , with
* zeros placed into the new leading bits .
* /
goog . math . Long . prototype . shiftRightUnsigned = function ( numBits ) {
numBits &= 63 ;
if ( numBits == 0 ) {
return this ;
} else {
var high = this . high _ ;
if ( numBits < 32 ) {
var low = this . low _ ;
return goog . math . Long . fromBits (
( low >>> numBits ) | ( high << ( 32 - numBits ) ) ,
high >>> numBits ) ;
} else if ( numBits == 32 ) {
return goog . math . Long . fromBits ( high , 0 ) ;
} else {
return goog . math . Long . fromBits ( high >>> ( numBits - 32 ) , 0 ) ;
}
}
} ;
//======= begin jsbn =======
var navigator = { appName : 'Modern Browser' } ; // polyfill a little
// Copyright (c) 2005 Tom Wu
// All Rights Reserved.
// http://www-cs-students.stanford.edu/~tjw/jsbn/
/ *
* Copyright ( c ) 2003 - 2005 Tom Wu
* All Rights Reserved .
*
* Permission is hereby granted , free of charge , to any person obtaining
* a copy of this software and associated documentation files ( the
* "Software" ) , to deal in the Software without restriction , including
* without limitation the rights to use , copy , modify , merge , publish ,
* distribute , sublicense , and / or sell copies of the Software , and to
* permit persons to whom the Software is furnished to do so , subject to
* the following conditions :
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software .
*
* THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND ,
* EXPRESS , IMPLIED OR OTHERWISE , INCLUDING WITHOUT LIMITATION , ANY
* WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE .
*
* IN NO EVENT SHALL TOM WU BE LIABLE FOR ANY SPECIAL , INCIDENTAL ,
* INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND , OR ANY DAMAGES WHATSOEVER
* RESULTING FROM LOSS OF USE , DATA OR PROFITS , WHETHER OR NOT ADVISED OF
* THE POSSIBILITY OF DAMAGE , AND ON ANY THEORY OF LIABILITY , ARISING OUT
* OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE .
*
* In addition , the following condition applies :
*
* All redistributions must retain an intact copy of this copyright notice
* and disclaimer .
* /
// Basic JavaScript BN library - subset useful for RSA encryption.
// Bits per digit
var dbits ;
// JavaScript engine analysis
var canary = 0xdeadbeefcafe ;
var j _lm = ( ( canary & 0xffffff ) == 0xefcafe ) ;
// (public) Constructor
function BigInteger ( a , b , c ) {
if ( a != null )
if ( "number" == typeof a ) this . fromNumber ( a , b , c ) ;
else if ( b == null && "string" != typeof a ) this . fromString ( a , 256 ) ;
else this . fromString ( a , b ) ;
}
// return new, unset BigInteger
function nbi ( ) { return new BigInteger ( null ) ; }
// am: Compute w_j += (x*this_i), propagate carries,
// c is initial carry, returns final carry.
// c < 3*dvalue, x < 2*dvalue, this_i < dvalue
// We need to select the fastest one that works in this environment.
// am1: use a single mult and divide to get the high bits,
// max digit bits should be 26 because
// max internal value = 2*dvalue^2-2*dvalue (< 2^53)
function am1 ( i , x , w , j , c , n ) {
while ( -- n >= 0 ) {
var v = x * this [ i ++ ] + w [ j ] + c ;
c = Math . floor ( v / 0x4000000 ) ;
w [ j ++ ] = v & 0x3ffffff ;
}
return c ;
}
// am2 avoids a big mult-and-extract completely.
// Max digit bits should be <= 30 because we do bitwise ops
// on values up to 2*hdvalue^2-hdvalue-1 (< 2^31)
function am2 ( i , x , w , j , c , n ) {
var xl = x & 0x7fff , xh = x >> 15 ;
while ( -- n >= 0 ) {
var l = this [ i ] & 0x7fff ;
var h = this [ i ++ ] >> 15 ;
var m = xh * l + h * xl ;
l = xl * l + ( ( m & 0x7fff ) << 15 ) + w [ j ] + ( c & 0x3fffffff ) ;
c = ( l >>> 30 ) + ( m >>> 15 ) + xh * h + ( c >>> 30 ) ;
w [ j ++ ] = l & 0x3fffffff ;
}
return c ;
}
// Alternately, set max digit bits to 28 since some
// browsers slow down when dealing with 32-bit numbers.
function am3 ( i , x , w , j , c , n ) {
var xl = x & 0x3fff , xh = x >> 14 ;
while ( -- n >= 0 ) {
var l = this [ i ] & 0x3fff ;
var h = this [ i ++ ] >> 14 ;
var m = xh * l + h * xl ;
l = xl * l + ( ( m & 0x3fff ) << 14 ) + w [ j ] + c ;
c = ( l >> 28 ) + ( m >> 14 ) + xh * h ;
w [ j ++ ] = l & 0xfffffff ;
}
return c ;
}
if ( j _lm && ( navigator . appName == "Microsoft Internet Explorer" ) ) {
BigInteger . prototype . am = am2 ;
dbits = 30 ;
}
else if ( j _lm && ( navigator . appName != "Netscape" ) ) {
BigInteger . prototype . am = am1 ;
dbits = 26 ;
}
else { // Mozilla/Netscape seems to prefer am3
BigInteger . prototype . am = am3 ;
dbits = 28 ;
}
BigInteger . prototype . DB = dbits ;
BigInteger . prototype . DM = ( ( 1 << dbits ) - 1 ) ;
BigInteger . prototype . DV = ( 1 << dbits ) ;
var BI _FP = 52 ;
BigInteger . prototype . FV = Math . pow ( 2 , BI _FP ) ;
BigInteger . prototype . F1 = BI _FP - dbits ;
BigInteger . prototype . F2 = 2 * dbits - BI _FP ;
// Digit conversions
var BI _RM = "0123456789abcdefghijklmnopqrstuvwxyz" ;
var BI _RC = new Array ( ) ;
var rr , vv ;
rr = "0" . charCodeAt ( 0 ) ;
for ( vv = 0 ; vv <= 9 ; ++ vv ) BI _RC [ rr ++ ] = vv ;
rr = "a" . charCodeAt ( 0 ) ;
for ( vv = 10 ; vv < 36 ; ++ vv ) BI _RC [ rr ++ ] = vv ;
rr = "A" . charCodeAt ( 0 ) ;
for ( vv = 10 ; vv < 36 ; ++ vv ) BI _RC [ rr ++ ] = vv ;
function int2char ( n ) { return BI _RM . charAt ( n ) ; }
function intAt ( s , i ) {
var c = BI _RC [ s . charCodeAt ( i ) ] ;
return ( c == null ) ? - 1 : c ;
}
// (protected) copy this to r
function bnpCopyTo ( r ) {
for ( var i = this . t - 1 ; i >= 0 ; -- i ) r [ i ] = this [ i ] ;
r . t = this . t ;
r . s = this . s ;
}
// (protected) set from integer value x, -DV <= x < DV
function bnpFromInt ( x ) {
this . t = 1 ;
this . s = ( x < 0 ) ? - 1 : 0 ;
if ( x > 0 ) this [ 0 ] = x ;
else if ( x < - 1 ) this [ 0 ] = x + DV ;
else this . t = 0 ;
}
// return bigint initialized to value
function nbv ( i ) { var r = nbi ( ) ; r . fromInt ( i ) ; return r ; }
// (protected) set from string and radix
function bnpFromString ( s , b ) {
var k ;
if ( b == 16 ) k = 4 ;
else if ( b == 8 ) k = 3 ;
else if ( b == 256 ) k = 8 ; // byte array
else if ( b == 2 ) k = 1 ;
else if ( b == 32 ) k = 5 ;
else if ( b == 4 ) k = 2 ;
else { this . fromRadix ( s , b ) ; return ; }
this . t = 0 ;
this . s = 0 ;
var i = s . length , mi = false , sh = 0 ;
while ( -- i >= 0 ) {
var x = ( k == 8 ) ? s [ i ] & 0xff : intAt ( s , i ) ;
if ( x < 0 ) {
if ( s . charAt ( i ) == "-" ) mi = true ;
continue ;
}
mi = false ;
if ( sh == 0 )
this [ this . t ++ ] = x ;
else if ( sh + k > this . DB ) {
this [ this . t - 1 ] |= ( x & ( ( 1 << ( this . DB - sh ) ) - 1 ) ) << sh ;
this [ this . t ++ ] = ( x >> ( this . DB - sh ) ) ;
}
else
this [ this . t - 1 ] |= x << sh ;
sh += k ;
if ( sh >= this . DB ) sh -= this . DB ;
}
if ( k == 8 && ( s [ 0 ] & 0x80 ) != 0 ) {
this . s = - 1 ;
if ( sh > 0 ) this [ this . t - 1 ] |= ( ( 1 << ( this . DB - sh ) ) - 1 ) << sh ;
}
this . clamp ( ) ;
if ( mi ) BigInteger . ZERO . subTo ( this , this ) ;
}
// (protected) clamp off excess high words
function bnpClamp ( ) {
var c = this . s & this . DM ;
while ( this . t > 0 && this [ this . t - 1 ] == c ) -- this . t ;
}
// (public) return string representation in given radix
function bnToString ( b ) {
if ( this . s < 0 ) return "-" + this . negate ( ) . toString ( b ) ;
var k ;
if ( b == 16 ) k = 4 ;
else if ( b == 8 ) k = 3 ;
else if ( b == 2 ) k = 1 ;
else if ( b == 32 ) k = 5 ;
else if ( b == 4 ) k = 2 ;
else return this . toRadix ( b ) ;
var km = ( 1 << k ) - 1 , d , m = false , r = "" , i = this . t ;
var p = this . DB - ( i * this . DB ) % k ;
if ( i -- > 0 ) {
if ( p < this . DB && ( d = this [ i ] >> p ) > 0 ) { m = true ; r = int2char ( d ) ; }
while ( i >= 0 ) {
if ( p < k ) {
d = ( this [ i ] & ( ( 1 << p ) - 1 ) ) << ( k - p ) ;
d |= this [ -- i ] >> ( p += this . DB - k ) ;
}
else {
d = ( this [ i ] >> ( p -= k ) ) & km ;
if ( p <= 0 ) { p += this . DB ; -- i ; }
}
if ( d > 0 ) m = true ;
if ( m ) r += int2char ( d ) ;
}
}
return m ? r : "0" ;
}
// (public) -this
function bnNegate ( ) { var r = nbi ( ) ; BigInteger . ZERO . subTo ( this , r ) ; return r ; }
// (public) |this|
function bnAbs ( ) { return ( this . s < 0 ) ? this . negate ( ) : this ; }
// (public) return + if this > a, - if this < a, 0 if equal
function bnCompareTo ( a ) {
var r = this . s - a . s ;
if ( r != 0 ) return r ;
var i = this . t ;
r = i - a . t ;
if ( r != 0 ) return ( this . s < 0 ) ? - r : r ;
while ( -- i >= 0 ) if ( ( r = this [ i ] - a [ i ] ) != 0 ) return r ;
return 0 ;
}
// returns bit length of the integer x
function nbits ( x ) {
var r = 1 , t ;
if ( ( t = x >>> 16 ) != 0 ) { x = t ; r += 16 ; }
if ( ( t = x >> 8 ) != 0 ) { x = t ; r += 8 ; }
if ( ( t = x >> 4 ) != 0 ) { x = t ; r += 4 ; }
if ( ( t = x >> 2 ) != 0 ) { x = t ; r += 2 ; }
if ( ( t = x >> 1 ) != 0 ) { x = t ; r += 1 ; }
return r ;
}
// (public) return the number of bits in "this"
function bnBitLength ( ) {
if ( this . t <= 0 ) return 0 ;
return this . DB * ( this . t - 1 ) + nbits ( this [ this . t - 1 ] ^ ( this . s & this . DM ) ) ;
}
// (protected) r = this << n*DB
function bnpDLShiftTo ( n , r ) {
var i ;
for ( i = this . t - 1 ; i >= 0 ; -- i ) r [ i + n ] = this [ i ] ;
for ( i = n - 1 ; i >= 0 ; -- i ) r [ i ] = 0 ;
r . t = this . t + n ;
r . s = this . s ;
}
// (protected) r = this >> n*DB
function bnpDRShiftTo ( n , r ) {
for ( var i = n ; i < this . t ; ++ i ) r [ i - n ] = this [ i ] ;
r . t = Math . max ( this . t - n , 0 ) ;
r . s = this . s ;
}
// (protected) r = this << n
function bnpLShiftTo ( n , r ) {
var bs = n % this . DB ;
var cbs = this . DB - bs ;
var bm = ( 1 << cbs ) - 1 ;
var ds = Math . floor ( n / this . DB ) , c = ( this . s << bs ) & this . DM , i ;
for ( i = this . t - 1 ; i >= 0 ; -- i ) {
r [ i + ds + 1 ] = ( this [ i ] >> cbs ) | c ;
c = ( this [ i ] & bm ) << bs ;
}
for ( i = ds - 1 ; i >= 0 ; -- i ) r [ i ] = 0 ;
r [ ds ] = c ;
r . t = this . t + ds + 1 ;
r . s = this . s ;
r . clamp ( ) ;
}
// (protected) r = this >> n
function bnpRShiftTo ( n , r ) {
r . s = this . s ;
var ds = Math . floor ( n / this . DB ) ;
if ( ds >= this . t ) { r . t = 0 ; return ; }
var bs = n % this . DB ;
var cbs = this . DB - bs ;
var bm = ( 1 << bs ) - 1 ;
r [ 0 ] = this [ ds ] >> bs ;
for ( var i = ds + 1 ; i < this . t ; ++ i ) {
r [ i - ds - 1 ] |= ( this [ i ] & bm ) << cbs ;
r [ i - ds ] = this [ i ] >> bs ;
}
if ( bs > 0 ) r [ this . t - ds - 1 ] |= ( this . s & bm ) << cbs ;
r . t = this . t - ds ;
r . clamp ( ) ;
}
// (protected) r = this - a
function bnpSubTo ( a , r ) {
var i = 0 , c = 0 , m = Math . min ( a . t , this . t ) ;
while ( i < m ) {
c += this [ i ] - a [ i ] ;
r [ i ++ ] = c & this . DM ;
c >>= this . DB ;
}
if ( a . t < this . t ) {
c -= a . s ;
while ( i < this . t ) {
c += this [ i ] ;
r [ i ++ ] = c & this . DM ;
c >>= this . DB ;
}
c += this . s ;
}
else {
c += this . s ;
while ( i < a . t ) {
c -= a [ i ] ;
r [ i ++ ] = c & this . DM ;
c >>= this . DB ;
}
c -= a . s ;
}
r . s = ( c < 0 ) ? - 1 : 0 ;
if ( c < - 1 ) r [ i ++ ] = this . DV + c ;
else if ( c > 0 ) r [ i ++ ] = c ;
r . t = i ;
r . clamp ( ) ;
}
// (protected) r = this * a, r != this,a (HAC 14.12)
// "this" should be the larger one if appropriate.
function bnpMultiplyTo ( a , r ) {
var x = this . abs ( ) , y = a . abs ( ) ;
var i = x . t ;
r . t = i + y . t ;
while ( -- i >= 0 ) r [ i ] = 0 ;
for ( i = 0 ; i < y . t ; ++ i ) r [ i + x . t ] = x . am ( 0 , y [ i ] , r , i , 0 , x . t ) ;
r . s = 0 ;
r . clamp ( ) ;
if ( this . s != a . s ) BigInteger . ZERO . subTo ( r , r ) ;
}
// (protected) r = this^2, r != this (HAC 14.16)
function bnpSquareTo ( r ) {
var x = this . abs ( ) ;
var i = r . t = 2 * x . t ;
while ( -- i >= 0 ) r [ i ] = 0 ;
for ( i = 0 ; i < x . t - 1 ; ++ i ) {
var c = x . am ( i , x [ i ] , r , 2 * i , 0 , 1 ) ;
if ( ( r [ i + x . t ] += x . am ( i + 1 , 2 * x [ i ] , r , 2 * i + 1 , c , x . t - i - 1 ) ) >= x . DV ) {
r [ i + x . t ] -= x . DV ;
r [ i + x . t + 1 ] = 1 ;
}
}
if ( r . t > 0 ) r [ r . t - 1 ] += x . am ( i , x [ i ] , r , 2 * i , 0 , 1 ) ;
r . s = 0 ;
r . clamp ( ) ;
}
// (protected) divide this by m, quotient and remainder to q, r (HAC 14.20)
// r != q, this != m. q or r may be null.
function bnpDivRemTo ( m , q , r ) {
var pm = m . abs ( ) ;
if ( pm . t <= 0 ) return ;
var pt = this . abs ( ) ;
if ( pt . t < pm . t ) {
if ( q != null ) q . fromInt ( 0 ) ;
if ( r != null ) this . copyTo ( r ) ;
return ;
}
if ( r == null ) r = nbi ( ) ;
var y = nbi ( ) , ts = this . s , ms = m . s ;
var nsh = this . DB - nbits ( pm [ pm . t - 1 ] ) ; // normalize modulus
if ( nsh > 0 ) { pm . lShiftTo ( nsh , y ) ; pt . lShiftTo ( nsh , r ) ; }
else { pm . copyTo ( y ) ; pt . copyTo ( r ) ; }
var ys = y . t ;
var y0 = y [ ys - 1 ] ;
if ( y0 == 0 ) return ;
var yt = y0 * ( 1 << this . F1 ) + ( ( ys > 1 ) ? y [ ys - 2 ] >> this . F2 : 0 ) ;
var d1 = this . FV / yt , d2 = ( 1 << this . F1 ) / yt , e = 1 << this . F2 ;
var i = r . t , j = i - ys , t = ( q == null ) ? nbi ( ) : q ;
y . dlShiftTo ( j , t ) ;
if ( r . compareTo ( t ) >= 0 ) {
r [ r . t ++ ] = 1 ;
r . subTo ( t , r ) ;
}
BigInteger . ONE . dlShiftTo ( ys , t ) ;
t . subTo ( y , y ) ; // "negative" y so we can replace sub with am later
while ( y . t < ys ) y [ y . t ++ ] = 0 ;
while ( -- j >= 0 ) {
// Estimate quotient digit
var qd = ( r [ -- i ] == y0 ) ? this . DM : Math . floor ( r [ i ] * d1 + ( r [ i - 1 ] + e ) * d2 ) ;
if ( ( r [ i ] += y . am ( 0 , qd , r , j , 0 , ys ) ) < qd ) { // Try it out
y . dlShiftTo ( j , t ) ;
r . subTo ( t , r ) ;
while ( r [ i ] < -- qd ) r . subTo ( t , r ) ;
}
}
if ( q != null ) {
r . drShiftTo ( ys , q ) ;
if ( ts != ms ) BigInteger . ZERO . subTo ( q , q ) ;
}
r . t = ys ;
r . clamp ( ) ;
if ( nsh > 0 ) r . rShiftTo ( nsh , r ) ; // Denormalize remainder
if ( ts < 0 ) BigInteger . ZERO . subTo ( r , r ) ;
}
// (public) this mod a
function bnMod ( a ) {
var r = nbi ( ) ;
this . abs ( ) . divRemTo ( a , null , r ) ;
if ( this . s < 0 && r . compareTo ( BigInteger . ZERO ) > 0 ) a . subTo ( r , r ) ;
return r ;
}
// Modular reduction using "classic" algorithm
function Classic ( m ) { this . m = m ; }
function cConvert ( x ) {
if ( x . s < 0 || x . compareTo ( this . m ) >= 0 ) return x . mod ( this . m ) ;
else return x ;
}
function cRevert ( x ) { return x ; }
function cReduce ( x ) { x . divRemTo ( this . m , null , x ) ; }
function cMulTo ( x , y , r ) { x . multiplyTo ( y , r ) ; this . reduce ( r ) ; }
function cSqrTo ( x , r ) { x . squareTo ( r ) ; this . reduce ( r ) ; }
Classic . prototype . convert = cConvert ;
Classic . prototype . revert = cRevert ;
Classic . prototype . reduce = cReduce ;
Classic . prototype . mulTo = cMulTo ;
Classic . prototype . sqrTo = cSqrTo ;
// (protected) return "-1/this % 2^DB"; useful for Mont. reduction
// justification:
// xy == 1 (mod m)
// xy = 1+km
// xy(2-xy) = (1+km)(1-km)
// x[y(2-xy)] = 1-k^2m^2
// x[y(2-xy)] == 1 (mod m^2)
// if y is 1/x mod m, then y(2-xy) is 1/x mod m^2
// should reduce x and y(2-xy) by m^2 at each step to keep size bounded.
// JS multiply "overflows" differently from C/C++, so care is needed here.
function bnpInvDigit ( ) {
if ( this . t < 1 ) return 0 ;
var x = this [ 0 ] ;
if ( ( x & 1 ) == 0 ) return 0 ;
var y = x & 3 ; // y == 1/x mod 2^2
y = ( y * ( 2 - ( x & 0xf ) * y ) ) & 0xf ; // y == 1/x mod 2^4
y = ( y * ( 2 - ( x & 0xff ) * y ) ) & 0xff ; // y == 1/x mod 2^8
y = ( y * ( 2 - ( ( ( x & 0xffff ) * y ) & 0xffff ) ) ) & 0xffff ; // y == 1/x mod 2^16
// last step - calculate inverse mod DV directly;
// assumes 16 < DB <= 32 and assumes ability to handle 48-bit ints
y = ( y * ( 2 - x * y % this . DV ) ) % this . DV ; // y == 1/x mod 2^dbits
// we really want the negative inverse, and -DV < y < DV
return ( y > 0 ) ? this . DV - y : - y ;
}
// Montgomery reduction
function Montgomery ( m ) {
this . m = m ;
this . mp = m . invDigit ( ) ;
this . mpl = this . mp & 0x7fff ;
this . mph = this . mp >> 15 ;
this . um = ( 1 << ( m . DB - 15 ) ) - 1 ;
this . mt2 = 2 * m . t ;
}
// xR mod m
function montConvert ( x ) {
var r = nbi ( ) ;
x . abs ( ) . dlShiftTo ( this . m . t , r ) ;
r . divRemTo ( this . m , null , r ) ;
if ( x . s < 0 && r . compareTo ( BigInteger . ZERO ) > 0 ) this . m . subTo ( r , r ) ;
return r ;
}
// x/R mod m
function montRevert ( x ) {
var r = nbi ( ) ;
x . copyTo ( r ) ;
this . reduce ( r ) ;
return r ;
}
// x = x/R mod m (HAC 14.32)
function montReduce ( x ) {
while ( x . t <= this . mt2 ) // pad x so am has enough room later
x [ x . t ++ ] = 0 ;
for ( var i = 0 ; i < this . m . t ; ++ i ) {
// faster way of calculating u0 = x[i]*mp mod DV
var j = x [ i ] & 0x7fff ;
var u0 = ( j * this . mpl + ( ( ( j * this . mph + ( x [ i ] >> 15 ) * this . mpl ) & this . um ) << 15 ) ) & x . DM ;
// use am to combine the multiply-shift-add into one call
j = i + this . m . t ;
x [ j ] += this . m . am ( 0 , u0 , x , i , 0 , this . m . t ) ;
// propagate carry
while ( x [ j ] >= x . DV ) { x [ j ] -= x . DV ; x [ ++ j ] ++ ; }
}
x . clamp ( ) ;
x . drShiftTo ( this . m . t , x ) ;
if ( x . compareTo ( this . m ) >= 0 ) x . subTo ( this . m , x ) ;
}
// r = "x^2/R mod m"; x != r
function montSqrTo ( x , r ) { x . squareTo ( r ) ; this . reduce ( r ) ; }
// r = "xy/R mod m"; x,y != r
function montMulTo ( x , y , r ) { x . multiplyTo ( y , r ) ; this . reduce ( r ) ; }
Montgomery . prototype . convert = montConvert ;
Montgomery . prototype . revert = montRevert ;
Montgomery . prototype . reduce = montReduce ;
Montgomery . prototype . mulTo = montMulTo ;
Montgomery . prototype . sqrTo = montSqrTo ;
// (protected) true iff this is even
function bnpIsEven ( ) { return ( ( this . t > 0 ) ? ( this [ 0 ] & 1 ) : this . s ) == 0 ; }
// (protected) this^e, e < 2^32, doing sqr and mul with "r" (HAC 14.79)
function bnpExp ( e , z ) {
if ( e > 0xffffffff || e < 1 ) return BigInteger . ONE ;
var r = nbi ( ) , r2 = nbi ( ) , g = z . convert ( this ) , i = nbits ( e ) - 1 ;
g . copyTo ( r ) ;
while ( -- i >= 0 ) {
z . sqrTo ( r , r2 ) ;
if ( ( e & ( 1 << i ) ) > 0 ) z . mulTo ( r2 , g , r ) ;
else { var t = r ; r = r2 ; r2 = t ; }
}
return z . revert ( r ) ;
}
// (public) this^e % m, 0 <= e < 2^32
function bnModPowInt ( e , m ) {
var z ;
if ( e < 256 || m . isEven ( ) ) z = new Classic ( m ) ; else z = new Montgomery ( m ) ;
return this . exp ( e , z ) ;
}
// protected
BigInteger . prototype . copyTo = bnpCopyTo ;
BigInteger . prototype . fromInt = bnpFromInt ;
BigInteger . prototype . fromString = bnpFromString ;
BigInteger . prototype . clamp = bnpClamp ;
BigInteger . prototype . dlShiftTo = bnpDLShiftTo ;
BigInteger . prototype . drShiftTo = bnpDRShiftTo ;
BigInteger . prototype . lShiftTo = bnpLShiftTo ;
BigInteger . prototype . rShiftTo = bnpRShiftTo ;
BigInteger . prototype . subTo = bnpSubTo ;
BigInteger . prototype . multiplyTo = bnpMultiplyTo ;
BigInteger . prototype . squareTo = bnpSquareTo ;
BigInteger . prototype . divRemTo = bnpDivRemTo ;
BigInteger . prototype . invDigit = bnpInvDigit ;
BigInteger . prototype . isEven = bnpIsEven ;
BigInteger . prototype . exp = bnpExp ;
// public
BigInteger . prototype . toString = bnToString ;
BigInteger . prototype . negate = bnNegate ;
BigInteger . prototype . abs = bnAbs ;
BigInteger . prototype . compareTo = bnCompareTo ;
BigInteger . prototype . bitLength = bnBitLength ;
BigInteger . prototype . mod = bnMod ;
BigInteger . prototype . modPowInt = bnModPowInt ;
// "constants"
BigInteger . ZERO = nbv ( 0 ) ;
BigInteger . ONE = nbv ( 1 ) ;
// jsbn2 stuff
// (protected) convert from radix string
function bnpFromRadix ( s , b ) {
this . fromInt ( 0 ) ;
if ( b == null ) b = 10 ;
var cs = this . chunkSize ( b ) ;
var d = Math . pow ( b , cs ) , mi = false , j = 0 , w = 0 ;
for ( var i = 0 ; i < s . length ; ++ i ) {
var x = intAt ( s , i ) ;
if ( x < 0 ) {
if ( s . charAt ( i ) == "-" && this . signum ( ) == 0 ) mi = true ;
continue ;
}
w = b * w + x ;
if ( ++ j >= cs ) {
this . dMultiply ( d ) ;
this . dAddOffset ( w , 0 ) ;
j = 0 ;
w = 0 ;
}
}
if ( j > 0 ) {
this . dMultiply ( Math . pow ( b , j ) ) ;
this . dAddOffset ( w , 0 ) ;
}
if ( mi ) BigInteger . ZERO . subTo ( this , this ) ;
}
// (protected) return x s.t. r^x < DV
function bnpChunkSize ( r ) { return Math . floor ( Math . LN2 * this . DB / Math . log ( r ) ) ; }
// (public) 0 if this == 0, 1 if this > 0
function bnSigNum ( ) {
if ( this . s < 0 ) return - 1 ;
else if ( this . t <= 0 || ( this . t == 1 && this [ 0 ] <= 0 ) ) return 0 ;
else return 1 ;
}
// (protected) this *= n, this >= 0, 1 < n < DV
function bnpDMultiply ( n ) {
this [ this . t ] = this . am ( 0 , n - 1 , this , 0 , 0 , this . t ) ;
++ this . t ;
this . clamp ( ) ;
}
// (protected) this += n << w words, this >= 0
function bnpDAddOffset ( n , w ) {
if ( n == 0 ) return ;
while ( this . t <= w ) this [ this . t ++ ] = 0 ;
this [ w ] += n ;
while ( this [ w ] >= this . DV ) {
this [ w ] -= this . DV ;
if ( ++ w >= this . t ) this [ this . t ++ ] = 0 ;
++ this [ w ] ;
}
}
// (protected) convert to radix string
function bnpToRadix ( b ) {
if ( b == null ) b = 10 ;
if ( this . signum ( ) == 0 || b < 2 || b > 36 ) return "0" ;
var cs = this . chunkSize ( b ) ;
var a = Math . pow ( b , cs ) ;
var d = nbv ( a ) , y = nbi ( ) , z = nbi ( ) , r = "" ;
this . divRemTo ( d , y , z ) ;
while ( y . signum ( ) > 0 ) {
r = ( a + z . intValue ( ) ) . toString ( b ) . substr ( 1 ) + r ;
y . divRemTo ( d , y , z ) ;
}
return z . intValue ( ) . toString ( b ) + r ;
}
// (public) return value as integer
function bnIntValue ( ) {
if ( this . s < 0 ) {
if ( this . t == 1 ) return this [ 0 ] - this . DV ;
else if ( this . t == 0 ) return - 1 ;
}
else if ( this . t == 1 ) return this [ 0 ] ;
else if ( this . t == 0 ) return 0 ;
// assumes 16 < DB < 32
return ( ( this [ 1 ] & ( ( 1 << ( 32 - this . DB ) ) - 1 ) ) << this . DB ) | this [ 0 ] ;
}
// (protected) r = this + a
function bnpAddTo ( a , r ) {
var i = 0 , c = 0 , m = Math . min ( a . t , this . t ) ;
while ( i < m ) {
c += this [ i ] + a [ i ] ;
r [ i ++ ] = c & this . DM ;
c >>= this . DB ;
}
if ( a . t < this . t ) {
c += a . s ;
while ( i < this . t ) {
c += this [ i ] ;
r [ i ++ ] = c & this . DM ;
c >>= this . DB ;
}
c += this . s ;
}
else {
c += this . s ;
while ( i < a . t ) {
c += a [ i ] ;
r [ i ++ ] = c & this . DM ;
c >>= this . DB ;
}
c += a . s ;
}
r . s = ( c < 0 ) ? - 1 : 0 ;
if ( c > 0 ) r [ i ++ ] = c ;
else if ( c < - 1 ) r [ i ++ ] = this . DV + c ;
r . t = i ;
r . clamp ( ) ;
}
BigInteger . prototype . fromRadix = bnpFromRadix ;
BigInteger . prototype . chunkSize = bnpChunkSize ;
BigInteger . prototype . signum = bnSigNum ;
BigInteger . prototype . dMultiply = bnpDMultiply ;
BigInteger . prototype . dAddOffset = bnpDAddOffset ;
BigInteger . prototype . toRadix = bnpToRadix ;
BigInteger . prototype . intValue = bnIntValue ;
BigInteger . prototype . addTo = bnpAddTo ;
//======= end jsbn =======
// Emscripten wrapper
var Wrapper = {
abs : function ( l , h ) {
var x = new goog . math . Long ( l , h ) ;
var ret ;
if ( x . isNegative ( ) ) {
ret = x . negate ( ) ;
} else {
ret = x ;
}
HEAP32 [ tempDoublePtr >> 2 ] = ret . low _ ;
HEAP32 [ tempDoublePtr + 4 >> 2 ] = ret . high _ ;
} ,
ensureTemps : function ( ) {
if ( Wrapper . ensuredTemps ) return ;
Wrapper . ensuredTemps = true ;
Wrapper . two32 = new BigInteger ( ) ;
Wrapper . two32 . fromString ( '4294967296' , 10 ) ;
Wrapper . two64 = new BigInteger ( ) ;
Wrapper . two64 . fromString ( '18446744073709551616' , 10 ) ;
Wrapper . temp1 = new BigInteger ( ) ;
Wrapper . temp2 = new BigInteger ( ) ;
} ,
lh2bignum : function ( l , h ) {
var a = new BigInteger ( ) ;
a . fromString ( h . toString ( ) , 10 ) ;
var b = new BigInteger ( ) ;
a . multiplyTo ( Wrapper . two32 , b ) ;
var c = new BigInteger ( ) ;
c . fromString ( l . toString ( ) , 10 ) ;
var d = new BigInteger ( ) ;
c . addTo ( b , d ) ;
return d ;
} ,
stringify : function ( l , h , unsigned ) {
var ret = new goog . math . Long ( l , h ) . toString ( ) ;
if ( unsigned && ret [ 0 ] == '-' ) {
// unsign slowly using jsbn bignums
Wrapper . ensureTemps ( ) ;
var bignum = new BigInteger ( ) ;
bignum . fromString ( ret , 10 ) ;
ret = new BigInteger ( ) ;
Wrapper . two64 . addTo ( bignum , ret ) ;
ret = ret . toString ( 10 ) ;
}
return ret ;
} ,
fromString : function ( str , base , min , max , unsigned ) {
Wrapper . ensureTemps ( ) ;
var bignum = new BigInteger ( ) ;
bignum . fromString ( str , base ) ;
var bigmin = new BigInteger ( ) ;
bigmin . fromString ( min , 10 ) ;
var bigmax = new BigInteger ( ) ;
bigmax . fromString ( max , 10 ) ;
if ( unsigned && bignum . compareTo ( BigInteger . ZERO ) < 0 ) {
var temp = new BigInteger ( ) ;
bignum . addTo ( Wrapper . two64 , temp ) ;
bignum = temp ;
}
var error = false ;
if ( bignum . compareTo ( bigmin ) < 0 ) {
bignum = bigmin ;
error = true ;
} else if ( bignum . compareTo ( bigmax ) > 0 ) {
bignum = bigmax ;
error = true ;
}
var ret = goog . math . Long . fromString ( bignum . toString ( ) ) ; // min-max checks should have clamped this to a range goog.math.Long can handle well
HEAP32 [ tempDoublePtr >> 2 ] = ret . low _ ;
HEAP32 [ tempDoublePtr + 4 >> 2 ] = ret . high _ ;
if ( error ) throw 'range error' ;
}
} ;
return Wrapper ;
} ) ( ) ;
//======= end closure i64 code =======
// === Auto-generated postamble setup entry stuff ===
Module [ 'callMain' ] = function callMain ( args ) {
assert ( runDependencies == 0 , 'cannot call main when async dependencies remain! (listen on __ATMAIN__)' ) ;
assert ( ! Module [ 'preRun' ] || Module [ 'preRun' ] . length == 0 , 'cannot call main when preRun functions remain to be called' ) ;
args = args || [ ] ;
ensureInitRuntime ( ) ;
var argc = args . length + 1 ;
function pad ( ) {
for ( var i = 0 ; i < 4 - 1 ; i ++ ) {
argv . push ( 0 ) ;
}
}
var argv = [ allocate ( intArrayFromString ( "/bin/this.program" ) , 'i8' , ALLOC _NORMAL ) ] ;
pad ( ) ;
for ( var i = 0 ; i < argc - 1 ; i = i + 1 ) {
argv . push ( allocate ( intArrayFromString ( args [ i ] ) , 'i8' , ALLOC _NORMAL ) ) ;
pad ( ) ;
}
argv . push ( 0 ) ;
argv = allocate ( argv , 'i32' , ALLOC _NORMAL ) ;
var ret ;
var initialStackTop = STACKTOP ;
try {
ret = Module [ '_main' ] ( argc , argv , 0 ) ;
}
catch ( e ) {
if ( e . name == 'ExitStatus' ) {
return e . status ;
} else if ( e == 'SimulateInfiniteLoop' ) {
Module [ 'noExitRuntime' ] = true ;
} else {
throw e ;
}
} finally {
STACKTOP = initialStackTop ;
}
return ret ;
}
function run ( args ) {
args = args || Module [ 'arguments' ] ;
if ( runDependencies > 0 ) {
Module . printErr ( 'run() called, but dependencies remain, so not running' ) ;
return 0 ;
}
if ( Module [ 'preRun' ] ) {
if ( typeof Module [ 'preRun' ] == 'function' ) Module [ 'preRun' ] = [ Module [ 'preRun' ] ] ;
var toRun = Module [ 'preRun' ] ;
Module [ 'preRun' ] = [ ] ;
for ( var i = toRun . length - 1 ; i >= 0 ; i -- ) {
toRun [ i ] ( ) ;
}
if ( runDependencies > 0 ) {
// a preRun added a dependency, run will be called later
return 0 ;
}
}
function doRun ( ) {
ensureInitRuntime ( ) ;
preMain ( ) ;
var ret = 0 ;
calledRun = true ;
if ( Module [ '_main' ] && shouldRunNow ) {
ret = Module [ 'callMain' ] ( args ) ;
if ( ! Module [ 'noExitRuntime' ] ) {
exitRuntime ( ) ;
}
}
if ( Module [ 'postRun' ] ) {
if ( typeof Module [ 'postRun' ] == 'function' ) Module [ 'postRun' ] = [ Module [ 'postRun' ] ] ;
while ( Module [ 'postRun' ] . length > 0 ) {
Module [ 'postRun' ] . pop ( ) ( ) ;
}
}
return ret ;
}
if ( Module [ 'setStatus' ] ) {
Module [ 'setStatus' ] ( 'Running...' ) ;
setTimeout ( function ( ) {
setTimeout ( function ( ) {
Module [ 'setStatus' ] ( '' ) ;
} , 1 ) ;
if ( ! ABORT ) doRun ( ) ;
} , 1 ) ;
return 0 ;
} else {
return doRun ( ) ;
}
}
Module [ 'run' ] = Module . run = run ;
// {{PRE_RUN_ADDITIONS}}
if ( Module [ 'preInit' ] ) {
if ( typeof Module [ 'preInit' ] == 'function' ) Module [ 'preInit' ] = [ Module [ 'preInit' ] ] ;
while ( Module [ 'preInit' ] . length > 0 ) {
Module [ 'preInit' ] . pop ( ) ( ) ;
}
}
// shouldRunNow refers to calling main(), not run().
var shouldRunNow = true ;
if ( Module [ 'noInitialRun' ] ) {
shouldRunNow = false ;
}
run ( ) ;
// {{POST_RUN_ADDITIONS}}
// {{MODULE_ADDITIONS}}
2015-01-13 15:49:38 -10:00
/ * v i m : t s = 4 : s w = 4 : e x p a n d t a b
*
* This program is free software : you can redistribute it and / or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation , either version 3 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU Lesser General Public License for more details .
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program . If not , see < http : //www.gnu.org/licenses/>.
* /
; ( function ( ) {
'use strict' ;
// Insert some bytes into the emscripten memory and return a pointer
function _allocate ( bytes ) {
var address = Module . _malloc ( bytes . length ) ;
Module . HEAPU8 . set ( bytes , address ) ;
return address ;
}
function _readBytes ( address , length , array ) {
array . set ( Module . HEAPU8 . subarray ( address , address + length ) ) ;
}
var basepoint = new Uint8Array ( 32 ) ;
basepoint [ 0 ] = 9 ;
window . curve25519 = {
keyPair : function ( privKey ) {
var priv = new Uint8Array ( privKey ) ;
priv [ 0 ] &= 248 ;
priv [ 31 ] &= 127 ;
priv [ 31 ] |= 64
// Where to store the result
var publicKey _ptr = Module . _malloc ( 32 ) ;
// Get a pointer to the private key
var privateKey _ptr = _allocate ( priv ) ;
// The basepoint for generating public keys
var basepoint _ptr = _allocate ( basepoint ) ;
// The return value is just 0, the operation is done in place
var err = Module . _curve25519 _donna ( publicKey _ptr ,
privateKey _ptr ,
basepoint _ptr ) ;
var res = new Uint8Array ( 32 ) ;
_readBytes ( publicKey _ptr , 32 , res ) ;
2015-02-11 12:49:17 -08:00
Module . _free ( publicKey _ptr ) ;
Module . _free ( privateKey _ptr ) ;
Module . _free ( basepoint _ptr ) ;
2015-01-13 15:49:38 -10:00
return Promise . resolve ( { pubKey : res . buffer , privKey : privKey } ) ;
} ,
sharedSecret : function ( pubKey , privKey ) {
// Where to store the result
var sharedKey _ptr = Module . _malloc ( 32 ) ;
// Get a pointer to our private key
var privateKey _ptr = _allocate ( new Uint8Array ( privKey ) ) ;
// Get a pointer to their public key, the basepoint when you're
// generating a shared secret
var basepoint _ptr = _allocate ( new Uint8Array ( pubKey ) ) ;
// Return value is 0 here too of course
var err = Module . _curve25519 _donna ( sharedKey _ptr ,
privateKey _ptr ,
basepoint _ptr ) ;
var res = new Uint8Array ( 32 ) ;
_readBytes ( sharedKey _ptr , 32 , res ) ;
2015-02-11 12:49:17 -08:00
Module . _free ( sharedKey _ptr ) ;
Module . _free ( privateKey _ptr ) ;
Module . _free ( basepoint _ptr ) ;
2015-01-13 15:49:38 -10:00
return Promise . resolve ( res . buffer ) ;
} ,
sign : function ( privKey , message ) {
// Where to store the result
2015-02-11 12:49:17 -08:00
var signature _ptr = Module . _malloc ( 64 ) ;
2015-01-13 15:49:38 -10:00
// Get a pointer to our private key
var privateKey _ptr = _allocate ( new Uint8Array ( privKey ) ) ;
// Get a pointer to the message
var message _ptr = _allocate ( new Uint8Array ( message ) ) ;
var err = Module . _curve25519 _sign ( signature _ptr ,
privateKey _ptr ,
message _ptr ,
message . byteLength ) ;
var res = new Uint8Array ( 64 ) ;
_readBytes ( signature _ptr , 64 , res ) ;
2015-02-11 12:49:17 -08:00
Module . _free ( signature _ptr ) ;
Module . _free ( privateKey _ptr ) ;
Module . _free ( message _ptr ) ;
2015-01-13 15:49:38 -10:00
return Promise . resolve ( res . buffer ) ;
} ,
verify : function ( pubKey , message , sig ) {
// Get a pointer to their public key
var publicKey _ptr = _allocate ( new Uint8Array ( pubKey ) ) ;
// Get a pointer to the signature
var signature _ptr = _allocate ( new Uint8Array ( sig ) ) ;
// Get a pointer to the message
var message _ptr = _allocate ( new Uint8Array ( message ) ) ;
var res = Module . _curve25519 _verify ( signature _ptr ,
publicKey _ptr ,
message _ptr ,
message . byteLength ) ;
2015-02-11 12:49:17 -08:00
Module . _free ( publicKey _ptr ) ;
Module . _free ( signature _ptr ) ;
Module . _free ( message _ptr ) ;
2015-01-13 15:49:38 -10:00
return new Promise ( function ( resolve , reject ) {
if ( res !== 0 ) {
reject ( new Error ( "Invalid signature" ) ) ;
} else {
resolve ( ) ;
}
} ) ;
}
} ;
} ) ( ) ;
} ) ( ) ;
; ( function ( ) {
/ * *
* CryptoJS core components .
* /
var CryptoJS = CryptoJS || ( function ( Math , undefined ) {
/ * *
* CryptoJS namespace .
* /
var C = { } ;
/ * *
* Library namespace .
* /
var C _lib = C . lib = { } ;
/ * *
* Base object for prototypal inheritance .
* /
var Base = C _lib . Base = ( function ( ) {
function F ( ) { }
return {
/ * *
* Creates a new object that inherits from this object .
*
* @ param { Object } overrides Properties to copy into the new object .
*
* @ return { Object } The new object .
*
* @ static
*
* @ example
*
* var MyType = CryptoJS . lib . Base . extend ( {
* field : 'value' ,
*
* method : function ( ) {
* }
* } ) ;
* /
extend : function ( overrides ) {
// Spawn
F . prototype = this ;
var subtype = new F ( ) ;
// Augment
if ( overrides ) {
subtype . mixIn ( overrides ) ;
}
// Create default initializer
if ( ! subtype . hasOwnProperty ( 'init' ) ) {
subtype . init = function ( ) {
subtype . $super . init . apply ( this , arguments ) ;
} ;
}
// Initializer's prototype is the subtype object
subtype . init . prototype = subtype ;
// Reference supertype
subtype . $super = this ;
return subtype ;
} ,
/ * *
* Extends this object and runs the init method .
* Arguments to create ( ) will be passed to init ( ) .
*
* @ return { Object } The new object .
*
* @ static
*
* @ example
*
* var instance = MyType . create ( ) ;
* /
create : function ( ) {
var instance = this . extend ( ) ;
instance . init . apply ( instance , arguments ) ;
return instance ;
} ,
/ * *
* Initializes a newly created object .
* Override this method to add some logic when your objects are created .
*
* @ example
*
* var MyType = CryptoJS . lib . Base . extend ( {
* init : function ( ) {
* // ...
* }
* } ) ;
* /
init : function ( ) {
} ,
/ * *
* Copies properties into this object .
*
* @ param { Object } properties The properties to mix in .
*
* @ example
*
* MyType . mixIn ( {
* field : 'value'
* } ) ;
* /
mixIn : function ( properties ) {
for ( var propertyName in properties ) {
if ( properties . hasOwnProperty ( propertyName ) ) {
this [ propertyName ] = properties [ propertyName ] ;
}
}
// IE won't copy toString using the loop above
if ( properties . hasOwnProperty ( 'toString' ) ) {
this . toString = properties . toString ;
}
} ,
/ * *
* Creates a copy of this object .
*
* @ return { Object } The clone .
*
* @ example
*
* var clone = instance . clone ( ) ;
* /
clone : function ( ) {
return this . init . prototype . extend ( this ) ;
}
} ;
} ( ) ) ;
/ * *
* An array of 32 - bit words .
*
* @ property { Array } words The array of 32 - bit words .
* @ property { number } sigBytes The number of significant bytes in this word array .
* /
var WordArray = C _lib . WordArray = Base . extend ( {
/ * *
* Initializes a newly created word array .
*
* @ param { Array } words ( Optional ) An array of 32 - bit words .
* @ param { number } sigBytes ( Optional ) The number of significant bytes in the words .
*
* @ example
*
* var wordArray = CryptoJS . lib . WordArray . create ( ) ;
* var wordArray = CryptoJS . lib . WordArray . create ( [ 0x00010203 , 0x04050607 ] ) ;
* var wordArray = CryptoJS . lib . WordArray . create ( [ 0x00010203 , 0x04050607 ] , 6 ) ;
* /
init : function ( words , sigBytes ) {
words = this . words = words || [ ] ;
if ( sigBytes != undefined ) {
this . sigBytes = sigBytes ;
} else {
this . sigBytes = words . length * 4 ;
}
} ,
/ * *
* Converts this word array to a string .
*
* @ param { Encoder } encoder ( Optional ) The encoding strategy to use . Default : CryptoJS . enc . Hex
*
* @ return { string } The stringified word array .
*
* @ example
*
* var string = wordArray + '' ;
* var string = wordArray . toString ( ) ;
* var string = wordArray . toString ( CryptoJS . enc . Utf8 ) ;
* /
toString : function ( encoder ) {
return ( encoder || Hex ) . stringify ( this ) ;
} ,
/ * *
* Concatenates a word array to this word array .
*
* @ param { WordArray } wordArray The word array to append .
*
* @ return { WordArray } This word array .
*
* @ example
*
* wordArray1 . concat ( wordArray2 ) ;
* /
concat : function ( wordArray ) {
// Shortcuts
var thisWords = this . words ;
var thatWords = wordArray . words ;
var thisSigBytes = this . sigBytes ;
var thatSigBytes = wordArray . sigBytes ;
// Clamp excess bits
this . clamp ( ) ;
// Concat
if ( thisSigBytes % 4 ) {
// Copy one byte at a time
for ( var i = 0 ; i < thatSigBytes ; i ++ ) {
var thatByte = ( thatWords [ i >>> 2 ] >>> ( 24 - ( i % 4 ) * 8 ) ) & 0xff ;
thisWords [ ( thisSigBytes + i ) >>> 2 ] |= thatByte << ( 24 - ( ( thisSigBytes + i ) % 4 ) * 8 ) ;
}
} else if ( thatWords . length > 0xffff ) {
// Copy one word at a time
for ( var i = 0 ; i < thatSigBytes ; i += 4 ) {
thisWords [ ( thisSigBytes + i ) >>> 2 ] = thatWords [ i >>> 2 ] ;
}
} else {
// Copy all words at once
thisWords . push . apply ( thisWords , thatWords ) ;
}
this . sigBytes += thatSigBytes ;
// Chainable
return this ;
} ,
/ * *
* Removes insignificant bits .
*
* @ example
*
* wordArray . clamp ( ) ;
* /
clamp : function ( ) {
// Shortcuts
var words = this . words ;
var sigBytes = this . sigBytes ;
// Clamp
words [ sigBytes >>> 2 ] &= 0xffffffff << ( 32 - ( sigBytes % 4 ) * 8 ) ;
words . length = Math . ceil ( sigBytes / 4 ) ;
} ,
/ * *
* Creates a copy of this word array .
*
* @ return { WordArray } The clone .
*
* @ example
*
* var clone = wordArray . clone ( ) ;
* /
clone : function ( ) {
var clone = Base . clone . call ( this ) ;
clone . words = this . words . slice ( 0 ) ;
return clone ;
} ,
/ * *
* Creates a word array filled with random bytes .
*
* @ param { number } nBytes The number of random bytes to generate .
*
* @ return { WordArray } The random word array .
*
* @ static
*
* @ example
*
* var wordArray = CryptoJS . lib . WordArray . random ( 16 ) ;
* /
random : function ( nBytes ) {
var words = [ ] ;
for ( var i = 0 ; i < nBytes ; i += 4 ) {
words . push ( ( Math . random ( ) * 0x100000000 ) | 0 ) ;
}
return new WordArray . init ( words , nBytes ) ;
}
} ) ;
/ * *
* Encoder namespace .
* /
var C _enc = C . enc = { } ;
/ * *
* Hex encoding strategy .
* /
var Hex = C _enc . Hex = {
/ * *
* Converts a word array to a hex string .
*
* @ param { WordArray } wordArray The word array .
*
* @ return { string } The hex string .
*
* @ static
*
* @ example
*
* var hexString = CryptoJS . enc . Hex . stringify ( wordArray ) ;
* /
stringify : function ( wordArray ) {
// Shortcuts
var words = wordArray . words ;
var sigBytes = wordArray . sigBytes ;
// Convert
var hexChars = [ ] ;
for ( var i = 0 ; i < sigBytes ; i ++ ) {
var bite = ( words [ i >>> 2 ] >>> ( 24 - ( i % 4 ) * 8 ) ) & 0xff ;
hexChars . push ( ( bite >>> 4 ) . toString ( 16 ) ) ;
hexChars . push ( ( bite & 0x0f ) . toString ( 16 ) ) ;
}
return hexChars . join ( '' ) ;
} ,
/ * *
* Converts a hex string to a word array .
*
* @ param { string } hexStr The hex string .
*
* @ return { WordArray } The word array .
*
* @ static
*
* @ example
*
* var wordArray = CryptoJS . enc . Hex . parse ( hexString ) ;
* /
parse : function ( hexStr ) {
// Shortcut
var hexStrLength = hexStr . length ;
// Convert
var words = [ ] ;
for ( var i = 0 ; i < hexStrLength ; i += 2 ) {
words [ i >>> 3 ] |= parseInt ( hexStr . substr ( i , 2 ) , 16 ) << ( 24 - ( i % 8 ) * 4 ) ;
}
return new WordArray . init ( words , hexStrLength / 2 ) ;
}
} ;
/ * *
* Latin1 encoding strategy .
* /
var Latin1 = C _enc . Latin1 = {
/ * *
* Converts a word array to a Latin1 string .
*
* @ param { WordArray } wordArray The word array .
*
* @ return { string } The Latin1 string .
*
* @ static
*
* @ example
*
* var latin1String = CryptoJS . enc . Latin1 . stringify ( wordArray ) ;
* /
stringify : function ( wordArray ) {
// Shortcuts
var words = wordArray . words ;
var sigBytes = wordArray . sigBytes ;
// Convert
var latin1Chars = [ ] ;
for ( var i = 0 ; i < sigBytes ; i ++ ) {
var bite = ( words [ i >>> 2 ] >>> ( 24 - ( i % 4 ) * 8 ) ) & 0xff ;
latin1Chars . push ( String . fromCharCode ( bite ) ) ;
}
return latin1Chars . join ( '' ) ;
} ,
/ * *
* Converts a Latin1 string to a word array .
*
* @ param { string } latin1Str The Latin1 string .
*
* @ return { WordArray } The word array .
*
* @ static
*
* @ example
*
* var wordArray = CryptoJS . enc . Latin1 . parse ( latin1String ) ;
* /
parse : function ( latin1Str ) {
// Shortcut
var latin1StrLength = latin1Str . length ;
// Convert
var words = [ ] ;
for ( var i = 0 ; i < latin1StrLength ; i ++ ) {
words [ i >>> 2 ] |= ( latin1Str . charCodeAt ( i ) & 0xff ) << ( 24 - ( i % 4 ) * 8 ) ;
}
return new WordArray . init ( words , latin1StrLength ) ;
}
} ;
/ * *
* UTF - 8 encoding strategy .
* /
var Utf8 = C _enc . Utf8 = {
/ * *
* Converts a word array to a UTF - 8 string .
*
* @ param { WordArray } wordArray The word array .
*
* @ return { string } The UTF - 8 string .
*
* @ static
*
* @ example
*
* var utf8String = CryptoJS . enc . Utf8 . stringify ( wordArray ) ;
* /
stringify : function ( wordArray ) {
try {
return decodeURIComponent ( escape ( Latin1 . stringify ( wordArray ) ) ) ;
} catch ( e ) {
throw new Error ( 'Malformed UTF-8 data' ) ;
}
} ,
/ * *
* Converts a UTF - 8 string to a word array .
*
* @ param { string } utf8Str The UTF - 8 string .
*
* @ return { WordArray } The word array .
*
* @ static
*
* @ example
*
* var wordArray = CryptoJS . enc . Utf8 . parse ( utf8String ) ;
* /
parse : function ( utf8Str ) {
return Latin1 . parse ( unescape ( encodeURIComponent ( utf8Str ) ) ) ;
}
} ;
/ * *
* Abstract buffered block algorithm template .
*
* The property blockSize must be implemented in a concrete subtype .
*
* @ property { number } _minBufferSize The number of blocks that should be kept unprocessed in the buffer . Default : 0
* /
var BufferedBlockAlgorithm = C _lib . BufferedBlockAlgorithm = Base . extend ( {
/ * *
* Resets this block algorithm ' s data buffer to its initial state .
*
* @ example
*
* bufferedBlockAlgorithm . reset ( ) ;
* /
reset : function ( ) {
// Initial values
this . _data = new WordArray . init ( ) ;
this . _nDataBytes = 0 ;
} ,
/ * *
* Adds new data to this block algorithm ' s buffer .
*
* @ param { WordArray | string } data The data to append . Strings are converted to a WordArray using UTF - 8.
*
* @ example
*
* bufferedBlockAlgorithm . _append ( 'data' ) ;
* bufferedBlockAlgorithm . _append ( wordArray ) ;
* /
_append : function ( data ) {
// Convert string to WordArray, else assume WordArray already
if ( typeof data == 'string' ) {
data = Utf8 . parse ( data ) ;
}
// Append
this . _data . concat ( data ) ;
this . _nDataBytes += data . sigBytes ;
} ,
/ * *
* Processes available data blocks .
*
* This method invokes _doProcessBlock ( offset ) , which must be implemented by a concrete subtype .
*
* @ param { boolean } doFlush Whether all blocks and partial blocks should be processed .
*
* @ return { WordArray } The processed data .
*
* @ example
*
* var processedData = bufferedBlockAlgorithm . _process ( ) ;
* var processedData = bufferedBlockAlgorithm . _process ( ! ! 'flush' ) ;
* /
_process : function ( doFlush ) {
// Shortcuts
var data = this . _data ;
var dataWords = data . words ;
var dataSigBytes = data . sigBytes ;
var blockSize = this . blockSize ;
var blockSizeBytes = blockSize * 4 ;
// Count blocks ready
var nBlocksReady = dataSigBytes / blockSizeBytes ;
if ( doFlush ) {
// Round up to include partial blocks
nBlocksReady = Math . ceil ( nBlocksReady ) ;
} else {
// Round down to include only full blocks,
// less the number of blocks that must remain in the buffer
nBlocksReady = Math . max ( ( nBlocksReady | 0 ) - this . _minBufferSize , 0 ) ;
}
// Count words ready
var nWordsReady = nBlocksReady * blockSize ;
// Count bytes ready
var nBytesReady = Math . min ( nWordsReady * 4 , dataSigBytes ) ;
// Process blocks
if ( nWordsReady ) {
for ( var offset = 0 ; offset < nWordsReady ; offset += blockSize ) {
// Perform concrete-algorithm logic
this . _doProcessBlock ( dataWords , offset ) ;
}
// Remove processed words
var processedWords = dataWords . splice ( 0 , nWordsReady ) ;
data . sigBytes -= nBytesReady ;
}
// Return processed words
return new WordArray . init ( processedWords , nBytesReady ) ;
} ,
/ * *
* Creates a copy of this object .
*
* @ return { Object } The clone .
*
* @ example
*
* var clone = bufferedBlockAlgorithm . clone ( ) ;
* /
clone : function ( ) {
var clone = Base . clone . call ( this ) ;
clone . _data = this . _data . clone ( ) ;
return clone ;
} ,
_minBufferSize : 0
} ) ;
/ * *
* Abstract hasher template .
*
* @ property { number } blockSize The number of 32 - bit words this hasher operates on . Default : 16 ( 512 bits )
* /
var Hasher = C _lib . Hasher = BufferedBlockAlgorithm . extend ( {
/ * *
* Configuration options .
* /
cfg : Base . extend ( ) ,
/ * *
* Initializes a newly created hasher .
*
* @ param { Object } cfg ( Optional ) The configuration options to use for this hash computation .
*
* @ example
*
* var hasher = CryptoJS . algo . SHA256 . create ( ) ;
* /
init : function ( cfg ) {
// Apply config defaults
this . cfg = this . cfg . extend ( cfg ) ;
// Set initial values
this . reset ( ) ;
} ,
/ * *
* Resets this hasher to its initial state .
*
* @ example
*
* hasher . reset ( ) ;
* /
reset : function ( ) {
// Reset data buffer
BufferedBlockAlgorithm . reset . call ( this ) ;
// Perform concrete-hasher logic
this . _doReset ( ) ;
} ,
/ * *
* Updates this hasher with a message .
*
* @ param { WordArray | string } messageUpdate The message to append .
*
* @ return { Hasher } This hasher .
*
* @ example
*
* hasher . update ( 'message' ) ;
* hasher . update ( wordArray ) ;
* /
update : function ( messageUpdate ) {
// Append
this . _append ( messageUpdate ) ;
// Update the hash
this . _process ( ) ;
// Chainable
return this ;
} ,
/ * *
* Finalizes the hash computation .
* Note that the finalize operation is effectively a destructive , read - once operation .
*
* @ param { WordArray | string } messageUpdate ( Optional ) A final message update .
*
* @ return { WordArray } The hash .
*
* @ example
*
* var hash = hasher . finalize ( ) ;
* var hash = hasher . finalize ( 'message' ) ;
* var hash = hasher . finalize ( wordArray ) ;
* /
finalize : function ( messageUpdate ) {
// Final message update
if ( messageUpdate ) {
this . _append ( messageUpdate ) ;
}
// Perform concrete-hasher logic
var hash = this . _doFinalize ( ) ;
return hash ;
} ,
blockSize : 512 / 32 ,
/ * *
* Creates a shortcut function to a hasher ' s object interface .
*
* @ param { Hasher } hasher The hasher to create a helper for .
*
* @ return { Function } The shortcut function .
*
* @ static
*
* @ example
*
* var SHA256 = CryptoJS . lib . Hasher . _createHelper ( CryptoJS . algo . SHA256 ) ;
* /
_createHelper : function ( hasher ) {
return function ( message , cfg ) {
return new hasher . init ( cfg ) . finalize ( message ) ;
} ;
} ,
/ * *
* Creates a shortcut function to the HMAC ' s object interface .
*
* @ param { Hasher } hasher The hasher to use in this HMAC helper .
*
* @ return { Function } The shortcut function .
*
* @ static
*
* @ example
*
* var HmacSHA256 = CryptoJS . lib . Hasher . _createHmacHelper ( CryptoJS . algo . SHA256 ) ;
* /
_createHmacHelper : function ( hasher ) {
return function ( message , key ) {
return new C _algo . HMAC . init ( hasher , key ) . finalize ( message ) ;
} ;
}
} ) ;
/ * *
* Algorithm namespace .
* /
var C _algo = C . algo = { } ;
return C ;
} ( Math ) ) ;
( function ( Math ) {
// Shortcuts
var C = CryptoJS ;
var C _lib = C . lib ;
var WordArray = C _lib . WordArray ;
var Hasher = C _lib . Hasher ;
var C _algo = C . algo ;
// Initialization and round constants tables
var H = [ ] ;
var K = [ ] ;
// Compute constants
( function ( ) {
function isPrime ( n ) {
var sqrtN = Math . sqrt ( n ) ;
for ( var factor = 2 ; factor <= sqrtN ; factor ++ ) {
if ( ! ( n % factor ) ) {
return false ;
}
}
return true ;
}
function getFractionalBits ( n ) {
return ( ( n - ( n | 0 ) ) * 0x100000000 ) | 0 ;
}
var n = 2 ;
var nPrime = 0 ;
while ( nPrime < 64 ) {
if ( isPrime ( n ) ) {
if ( nPrime < 8 ) {
H [ nPrime ] = getFractionalBits ( Math . pow ( n , 1 / 2 ) ) ;
}
K [ nPrime ] = getFractionalBits ( Math . pow ( n , 1 / 3 ) ) ;
nPrime ++ ;
}
n ++ ;
}
} ( ) ) ;
// Reusable object
var W = [ ] ;
/ * *
* SHA - 256 hash algorithm .
* /
var SHA256 = C _algo . SHA256 = Hasher . extend ( {
_doReset : function ( ) {
this . _hash = new WordArray . init ( H . slice ( 0 ) ) ;
} ,
_doProcessBlock : function ( M , offset ) {
// Shortcut
var H = this . _hash . words ;
// Working variables
var a = H [ 0 ] ;
var b = H [ 1 ] ;
var c = H [ 2 ] ;
var d = H [ 3 ] ;
var e = H [ 4 ] ;
var f = H [ 5 ] ;
var g = H [ 6 ] ;
var h = H [ 7 ] ;
// Computation
for ( var i = 0 ; i < 64 ; i ++ ) {
if ( i < 16 ) {
W [ i ] = M [ offset + i ] | 0 ;
} else {
var gamma0x = W [ i - 15 ] ;
var gamma0 = ( ( gamma0x << 25 ) | ( gamma0x >>> 7 ) ) ^
( ( gamma0x << 14 ) | ( gamma0x >>> 18 ) ) ^
( gamma0x >>> 3 ) ;
var gamma1x = W [ i - 2 ] ;
var gamma1 = ( ( gamma1x << 15 ) | ( gamma1x >>> 17 ) ) ^
( ( gamma1x << 13 ) | ( gamma1x >>> 19 ) ) ^
( gamma1x >>> 10 ) ;
W [ i ] = gamma0 + W [ i - 7 ] + gamma1 + W [ i - 16 ] ;
}
var ch = ( e & f ) ^ ( ~ e & g ) ;
var maj = ( a & b ) ^ ( a & c ) ^ ( b & c ) ;
var sigma0 = ( ( a << 30 ) | ( a >>> 2 ) ) ^ ( ( a << 19 ) | ( a >>> 13 ) ) ^ ( ( a << 10 ) | ( a >>> 22 ) ) ;
var sigma1 = ( ( e << 26 ) | ( e >>> 6 ) ) ^ ( ( e << 21 ) | ( e >>> 11 ) ) ^ ( ( e << 7 ) | ( e >>> 25 ) ) ;
var t1 = h + sigma1 + ch + K [ i ] + W [ i ] ;
var t2 = sigma0 + maj ;
h = g ;
g = f ;
f = e ;
e = ( d + t1 ) | 0 ;
d = c ;
c = b ;
b = a ;
a = ( t1 + t2 ) | 0 ;
}
// Intermediate hash value
H [ 0 ] = ( H [ 0 ] + a ) | 0 ;
H [ 1 ] = ( H [ 1 ] + b ) | 0 ;
H [ 2 ] = ( H [ 2 ] + c ) | 0 ;
H [ 3 ] = ( H [ 3 ] + d ) | 0 ;
H [ 4 ] = ( H [ 4 ] + e ) | 0 ;
H [ 5 ] = ( H [ 5 ] + f ) | 0 ;
H [ 6 ] = ( H [ 6 ] + g ) | 0 ;
H [ 7 ] = ( H [ 7 ] + h ) | 0 ;
} ,
_doFinalize : function ( ) {
// Shortcuts
var data = this . _data ;
var dataWords = data . words ;
var nBitsTotal = this . _nDataBytes * 8 ;
var nBitsLeft = data . sigBytes * 8 ;
// Add padding
dataWords [ nBitsLeft >>> 5 ] |= 0x80 << ( 24 - nBitsLeft % 32 ) ;
dataWords [ ( ( ( nBitsLeft + 64 ) >>> 9 ) << 4 ) + 14 ] = Math . floor ( nBitsTotal / 0x100000000 ) ;
dataWords [ ( ( ( nBitsLeft + 64 ) >>> 9 ) << 4 ) + 15 ] = nBitsTotal ;
data . sigBytes = dataWords . length * 4 ;
// Hash final blocks
this . _process ( ) ;
// Return final computed hash
return this . _hash ;
} ,
clone : function ( ) {
var clone = Hasher . clone . call ( this ) ;
clone . _hash = this . _hash . clone ( ) ;
return clone ;
}
} ) ;
/ * *
* Shortcut function to the hasher ' s object interface .
*
* @ param { WordArray | string } message The message to hash .
*
* @ return { WordArray } The hash .
*
* @ static
*
* @ example
*
* var hash = CryptoJS . SHA256 ( 'message' ) ;
* var hash = CryptoJS . SHA256 ( wordArray ) ;
* /
C . SHA256 = Hasher . _createHelper ( SHA256 ) ;
/ * *
* Shortcut function to the HMAC ' s object interface .
*
* @ param { WordArray | string } message The message to hash .
* @ param { WordArray | string } key The secret key .
*
* @ return { WordArray } The HMAC .
*
* @ static
*
* @ example
*
* var hmac = CryptoJS . HmacSHA256 ( message , key ) ;
* /
C . HmacSHA256 = Hasher . _createHmacHelper ( SHA256 ) ;
} ( Math ) ) ;
( function ( ) {
// Shortcuts
var C = CryptoJS ;
var C _lib = C . lib ;
var Base = C _lib . Base ;
var C _enc = C . enc ;
var Utf8 = C _enc . Utf8 ;
var C _algo = C . algo ;
/ * *
* HMAC algorithm .
* /
var HMAC = C _algo . HMAC = Base . extend ( {
/ * *
* Initializes a newly created HMAC .
*
* @ param { Hasher } hasher The hash algorithm to use .
* @ param { WordArray | string } key The secret key .
*
* @ example
*
* var hmacHasher = CryptoJS . algo . HMAC . create ( CryptoJS . algo . SHA256 , key ) ;
* /
init : function ( hasher , key ) {
// Init hasher
hasher = this . _hasher = new hasher . init ( ) ;
// Convert string to WordArray, else assume WordArray already
if ( typeof key == 'string' ) {
key = Utf8 . parse ( key ) ;
}
// Shortcuts
var hasherBlockSize = hasher . blockSize ;
var hasherBlockSizeBytes = hasherBlockSize * 4 ;
// Allow arbitrary length keys
if ( key . sigBytes > hasherBlockSizeBytes ) {
key = hasher . finalize ( key ) ;
}
// Clamp excess bits
key . clamp ( ) ;
// Clone key for inner and outer pads
var oKey = this . _oKey = key . clone ( ) ;
var iKey = this . _iKey = key . clone ( ) ;
// Shortcuts
var oKeyWords = oKey . words ;
var iKeyWords = iKey . words ;
// XOR keys with pad constants
for ( var i = 0 ; i < hasherBlockSize ; i ++ ) {
oKeyWords [ i ] ^= 0x5c5c5c5c ;
iKeyWords [ i ] ^= 0x36363636 ;
}
oKey . sigBytes = iKey . sigBytes = hasherBlockSizeBytes ;
// Set initial values
this . reset ( ) ;
} ,
/ * *
* Resets this HMAC to its initial state .
*
* @ example
*
* hmacHasher . reset ( ) ;
* /
reset : function ( ) {
// Shortcut
var hasher = this . _hasher ;
// Reset
hasher . reset ( ) ;
hasher . update ( this . _iKey ) ;
} ,
/ * *
* Updates this HMAC with a message .
*
* @ param { WordArray | string } messageUpdate The message to append .
*
* @ return { HMAC } This HMAC instance .
*
* @ example
*
* hmacHasher . update ( 'message' ) ;
* hmacHasher . update ( wordArray ) ;
* /
update : function ( messageUpdate ) {
this . _hasher . update ( messageUpdate ) ;
// Chainable
return this ;
} ,
/ * *
* Finalizes the HMAC computation .
* Note that the finalize operation is effectively a destructive , read - once operation .
*
* @ param { WordArray | string } messageUpdate ( Optional ) A final message update .
*
* @ return { WordArray } The HMAC .
*
* @ example
*
* var hmac = hmacHasher . finalize ( ) ;
* var hmac = hmacHasher . finalize ( 'message' ) ;
* var hmac = hmacHasher . finalize ( wordArray ) ;
* /
finalize : function ( messageUpdate ) {
// Shortcut
var hasher = this . _hasher ;
// Compute HMAC
var innerHash = hasher . finalize ( messageUpdate ) ;
hasher . reset ( ) ;
var hmac = hasher . finalize ( this . _oKey . clone ( ) . concat ( innerHash ) ) ;
return hmac ;
}
} ) ;
} ( ) ) ;
( function ( ) {
// Shortcuts
var C = CryptoJS ;
var C _lib = C . lib ;
var WordArray = C _lib . WordArray ;
var C _enc = C . enc ;
/ * *
* Base64 encoding strategy .
* /
var Base64 = C _enc . Base64 = {
/ * *
* Converts a word array to a Base64 string .
*
* @ param { WordArray } wordArray The word array .
*
* @ return { string } The Base64 string .
*
* @ static
*
* @ example
*
* var base64String = CryptoJS . enc . Base64 . stringify ( wordArray ) ;
* /
stringify : function ( wordArray ) {
// Shortcuts
var words = wordArray . words ;
var sigBytes = wordArray . sigBytes ;
var map = this . _map ;
// Clamp excess bits
wordArray . clamp ( ) ;
// Convert
var base64Chars = [ ] ;
for ( var i = 0 ; i < sigBytes ; i += 3 ) {
var byte1 = ( words [ i >>> 2 ] >>> ( 24 - ( i % 4 ) * 8 ) ) & 0xff ;
var byte2 = ( words [ ( i + 1 ) >>> 2 ] >>> ( 24 - ( ( i + 1 ) % 4 ) * 8 ) ) & 0xff ;
var byte3 = ( words [ ( i + 2 ) >>> 2 ] >>> ( 24 - ( ( i + 2 ) % 4 ) * 8 ) ) & 0xff ;
var triplet = ( byte1 << 16 ) | ( byte2 << 8 ) | byte3 ;
for ( var j = 0 ; ( j < 4 ) && ( i + j * 0.75 < sigBytes ) ; j ++ ) {
base64Chars . push ( map . charAt ( ( triplet >>> ( 6 * ( 3 - j ) ) ) & 0x3f ) ) ;
}
}
// Add padding
var paddingChar = map . charAt ( 64 ) ;
if ( paddingChar ) {
while ( base64Chars . length % 4 ) {
base64Chars . push ( paddingChar ) ;
}
}
return base64Chars . join ( '' ) ;
} ,
/ * *
* Converts a Base64 string to a word array .
*
* @ param { string } base64Str The Base64 string .
*
* @ return { WordArray } The word array .
*
* @ static
*
* @ example
*
* var wordArray = CryptoJS . enc . Base64 . parse ( base64String ) ;
* /
parse : function ( base64Str ) {
// Shortcuts
var base64StrLength = base64Str . length ;
var map = this . _map ;
// Ignore padding
var paddingChar = map . charAt ( 64 ) ;
if ( paddingChar ) {
var paddingIndex = base64Str . indexOf ( paddingChar ) ;
if ( paddingIndex != - 1 ) {
base64StrLength = paddingIndex ;
}
}
// Convert
var words = [ ] ;
var nBytes = 0 ;
for ( var i = 0 ; i < base64StrLength ; i ++ ) {
if ( i % 4 ) {
var bits1 = map . indexOf ( base64Str . charAt ( i - 1 ) ) << ( ( i % 4 ) * 2 ) ;
var bits2 = map . indexOf ( base64Str . charAt ( i ) ) >>> ( 6 - ( i % 4 ) * 2 ) ;
words [ nBytes >>> 2 ] |= ( bits1 | bits2 ) << ( 24 - ( nBytes % 4 ) * 8 ) ;
nBytes ++ ;
}
}
return WordArray . create ( words , nBytes ) ;
} ,
_map : 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='
} ;
} ( ) ) ;
( function ( Math ) {
// Shortcuts
var C = CryptoJS ;
var C _lib = C . lib ;
var WordArray = C _lib . WordArray ;
var Hasher = C _lib . Hasher ;
var C _algo = C . algo ;
// Constants table
var T = [ ] ;
// Compute constants
( function ( ) {
for ( var i = 0 ; i < 64 ; i ++ ) {
T [ i ] = ( Math . abs ( Math . sin ( i + 1 ) ) * 0x100000000 ) | 0 ;
}
} ( ) ) ;
/ * *
* MD5 hash algorithm .
* /
var MD5 = C _algo . MD5 = Hasher . extend ( {
_doReset : function ( ) {
this . _hash = new WordArray . init ( [
0x67452301 , 0xefcdab89 ,
0x98badcfe , 0x10325476
] ) ;
} ,
_doProcessBlock : function ( M , offset ) {
// Swap endian
for ( var i = 0 ; i < 16 ; i ++ ) {
// Shortcuts
var offset _i = offset + i ;
var M _offset _i = M [ offset _i ] ;
M [ offset _i ] = (
( ( ( M _offset _i << 8 ) | ( M _offset _i >>> 24 ) ) & 0x00ff00ff ) |
( ( ( M _offset _i << 24 ) | ( M _offset _i >>> 8 ) ) & 0xff00ff00 )
) ;
}
// Shortcuts
var H = this . _hash . words ;
var M _offset _0 = M [ offset + 0 ] ;
var M _offset _1 = M [ offset + 1 ] ;
var M _offset _2 = M [ offset + 2 ] ;
var M _offset _3 = M [ offset + 3 ] ;
var M _offset _4 = M [ offset + 4 ] ;
var M _offset _5 = M [ offset + 5 ] ;
var M _offset _6 = M [ offset + 6 ] ;
var M _offset _7 = M [ offset + 7 ] ;
var M _offset _8 = M [ offset + 8 ] ;
var M _offset _9 = M [ offset + 9 ] ;
var M _offset _10 = M [ offset + 10 ] ;
var M _offset _11 = M [ offset + 11 ] ;
var M _offset _12 = M [ offset + 12 ] ;
var M _offset _13 = M [ offset + 13 ] ;
var M _offset _14 = M [ offset + 14 ] ;
var M _offset _15 = M [ offset + 15 ] ;
// Working varialbes
var a = H [ 0 ] ;
var b = H [ 1 ] ;
var c = H [ 2 ] ;
var d = H [ 3 ] ;
// Computation
a = FF ( a , b , c , d , M _offset _0 , 7 , T [ 0 ] ) ;
d = FF ( d , a , b , c , M _offset _1 , 12 , T [ 1 ] ) ;
c = FF ( c , d , a , b , M _offset _2 , 17 , T [ 2 ] ) ;
b = FF ( b , c , d , a , M _offset _3 , 22 , T [ 3 ] ) ;
a = FF ( a , b , c , d , M _offset _4 , 7 , T [ 4 ] ) ;
d = FF ( d , a , b , c , M _offset _5 , 12 , T [ 5 ] ) ;
c = FF ( c , d , a , b , M _offset _6 , 17 , T [ 6 ] ) ;
b = FF ( b , c , d , a , M _offset _7 , 22 , T [ 7 ] ) ;
a = FF ( a , b , c , d , M _offset _8 , 7 , T [ 8 ] ) ;
d = FF ( d , a , b , c , M _offset _9 , 12 , T [ 9 ] ) ;
c = FF ( c , d , a , b , M _offset _10 , 17 , T [ 10 ] ) ;
b = FF ( b , c , d , a , M _offset _11 , 22 , T [ 11 ] ) ;
a = FF ( a , b , c , d , M _offset _12 , 7 , T [ 12 ] ) ;
d = FF ( d , a , b , c , M _offset _13 , 12 , T [ 13 ] ) ;
c = FF ( c , d , a , b , M _offset _14 , 17 , T [ 14 ] ) ;
b = FF ( b , c , d , a , M _offset _15 , 22 , T [ 15 ] ) ;
a = GG ( a , b , c , d , M _offset _1 , 5 , T [ 16 ] ) ;
d = GG ( d , a , b , c , M _offset _6 , 9 , T [ 17 ] ) ;
c = GG ( c , d , a , b , M _offset _11 , 14 , T [ 18 ] ) ;
b = GG ( b , c , d , a , M _offset _0 , 20 , T [ 19 ] ) ;
a = GG ( a , b , c , d , M _offset _5 , 5 , T [ 20 ] ) ;
d = GG ( d , a , b , c , M _offset _10 , 9 , T [ 21 ] ) ;
c = GG ( c , d , a , b , M _offset _15 , 14 , T [ 22 ] ) ;
b = GG ( b , c , d , a , M _offset _4 , 20 , T [ 23 ] ) ;
a = GG ( a , b , c , d , M _offset _9 , 5 , T [ 24 ] ) ;
d = GG ( d , a , b , c , M _offset _14 , 9 , T [ 25 ] ) ;
c = GG ( c , d , a , b , M _offset _3 , 14 , T [ 26 ] ) ;
b = GG ( b , c , d , a , M _offset _8 , 20 , T [ 27 ] ) ;
a = GG ( a , b , c , d , M _offset _13 , 5 , T [ 28 ] ) ;
d = GG ( d , a , b , c , M _offset _2 , 9 , T [ 29 ] ) ;
c = GG ( c , d , a , b , M _offset _7 , 14 , T [ 30 ] ) ;
b = GG ( b , c , d , a , M _offset _12 , 20 , T [ 31 ] ) ;
a = HH ( a , b , c , d , M _offset _5 , 4 , T [ 32 ] ) ;
d = HH ( d , a , b , c , M _offset _8 , 11 , T [ 33 ] ) ;
c = HH ( c , d , a , b , M _offset _11 , 16 , T [ 34 ] ) ;
b = HH ( b , c , d , a , M _offset _14 , 23 , T [ 35 ] ) ;
a = HH ( a , b , c , d , M _offset _1 , 4 , T [ 36 ] ) ;
d = HH ( d , a , b , c , M _offset _4 , 11 , T [ 37 ] ) ;
c = HH ( c , d , a , b , M _offset _7 , 16 , T [ 38 ] ) ;
b = HH ( b , c , d , a , M _offset _10 , 23 , T [ 39 ] ) ;
a = HH ( a , b , c , d , M _offset _13 , 4 , T [ 40 ] ) ;
d = HH ( d , a , b , c , M _offset _0 , 11 , T [ 41 ] ) ;
c = HH ( c , d , a , b , M _offset _3 , 16 , T [ 42 ] ) ;
b = HH ( b , c , d , a , M _offset _6 , 23 , T [ 43 ] ) ;
a = HH ( a , b , c , d , M _offset _9 , 4 , T [ 44 ] ) ;
d = HH ( d , a , b , c , M _offset _12 , 11 , T [ 45 ] ) ;
c = HH ( c , d , a , b , M _offset _15 , 16 , T [ 46 ] ) ;
b = HH ( b , c , d , a , M _offset _2 , 23 , T [ 47 ] ) ;
a = II ( a , b , c , d , M _offset _0 , 6 , T [ 48 ] ) ;
d = II ( d , a , b , c , M _offset _7 , 10 , T [ 49 ] ) ;
c = II ( c , d , a , b , M _offset _14 , 15 , T [ 50 ] ) ;
b = II ( b , c , d , a , M _offset _5 , 21 , T [ 51 ] ) ;
a = II ( a , b , c , d , M _offset _12 , 6 , T [ 52 ] ) ;
d = II ( d , a , b , c , M _offset _3 , 10 , T [ 53 ] ) ;
c = II ( c , d , a , b , M _offset _10 , 15 , T [ 54 ] ) ;
b = II ( b , c , d , a , M _offset _1 , 21 , T [ 55 ] ) ;
a = II ( a , b , c , d , M _offset _8 , 6 , T [ 56 ] ) ;
d = II ( d , a , b , c , M _offset _15 , 10 , T [ 57 ] ) ;
c = II ( c , d , a , b , M _offset _6 , 15 , T [ 58 ] ) ;
b = II ( b , c , d , a , M _offset _13 , 21 , T [ 59 ] ) ;
a = II ( a , b , c , d , M _offset _4 , 6 , T [ 60 ] ) ;
d = II ( d , a , b , c , M _offset _11 , 10 , T [ 61 ] ) ;
c = II ( c , d , a , b , M _offset _2 , 15 , T [ 62 ] ) ;
b = II ( b , c , d , a , M _offset _9 , 21 , T [ 63 ] ) ;
// Intermediate hash value
H [ 0 ] = ( H [ 0 ] + a ) | 0 ;
H [ 1 ] = ( H [ 1 ] + b ) | 0 ;
H [ 2 ] = ( H [ 2 ] + c ) | 0 ;
H [ 3 ] = ( H [ 3 ] + d ) | 0 ;
} ,
_doFinalize : function ( ) {
// Shortcuts
var data = this . _data ;
var dataWords = data . words ;
var nBitsTotal = this . _nDataBytes * 8 ;
var nBitsLeft = data . sigBytes * 8 ;
// Add padding
dataWords [ nBitsLeft >>> 5 ] |= 0x80 << ( 24 - nBitsLeft % 32 ) ;
var nBitsTotalH = Math . floor ( nBitsTotal / 0x100000000 ) ;
var nBitsTotalL = nBitsTotal ;
dataWords [ ( ( ( nBitsLeft + 64 ) >>> 9 ) << 4 ) + 15 ] = (
( ( ( nBitsTotalH << 8 ) | ( nBitsTotalH >>> 24 ) ) & 0x00ff00ff ) |
( ( ( nBitsTotalH << 24 ) | ( nBitsTotalH >>> 8 ) ) & 0xff00ff00 )
) ;
dataWords [ ( ( ( nBitsLeft + 64 ) >>> 9 ) << 4 ) + 14 ] = (
( ( ( nBitsTotalL << 8 ) | ( nBitsTotalL >>> 24 ) ) & 0x00ff00ff ) |
( ( ( nBitsTotalL << 24 ) | ( nBitsTotalL >>> 8 ) ) & 0xff00ff00 )
) ;
data . sigBytes = ( dataWords . length + 1 ) * 4 ;
// Hash final blocks
this . _process ( ) ;
// Shortcuts
var hash = this . _hash ;
var H = hash . words ;
// Swap endian
for ( var i = 0 ; i < 4 ; i ++ ) {
// Shortcut
var H _i = H [ i ] ;
H [ i ] = ( ( ( H _i << 8 ) | ( H _i >>> 24 ) ) & 0x00ff00ff ) |
( ( ( H _i << 24 ) | ( H _i >>> 8 ) ) & 0xff00ff00 ) ;
}
// Return final computed hash
return hash ;
} ,
clone : function ( ) {
var clone = Hasher . clone . call ( this ) ;
clone . _hash = this . _hash . clone ( ) ;
return clone ;
}
} ) ;
function FF ( a , b , c , d , x , s , t ) {
var n = a + ( ( b & c ) | ( ~ b & d ) ) + x + t ;
return ( ( n << s ) | ( n >>> ( 32 - s ) ) ) + b ;
}
function GG ( a , b , c , d , x , s , t ) {
var n = a + ( ( b & d ) | ( c & ~ d ) ) + x + t ;
return ( ( n << s ) | ( n >>> ( 32 - s ) ) ) + b ;
}
function HH ( a , b , c , d , x , s , t ) {
var n = a + ( b ^ c ^ d ) + x + t ;
return ( ( n << s ) | ( n >>> ( 32 - s ) ) ) + b ;
}
function II ( a , b , c , d , x , s , t ) {
var n = a + ( c ^ ( b | ~ d ) ) + x + t ;
return ( ( n << s ) | ( n >>> ( 32 - s ) ) ) + b ;
}
/ * *
* Shortcut function to the hasher ' s object interface .
*
* @ param { WordArray | string } message The message to hash .
*
* @ return { WordArray } The hash .
*
* @ static
*
* @ example
*
* var hash = CryptoJS . MD5 ( 'message' ) ;
* var hash = CryptoJS . MD5 ( wordArray ) ;
* /
C . MD5 = Hasher . _createHelper ( MD5 ) ;
/ * *
* Shortcut function to the HMAC ' s object interface .
*
* @ param { WordArray | string } message The message to hash .
* @ param { WordArray | string } key The secret key .
*
* @ return { WordArray } The HMAC .
*
* @ static
*
* @ example
*
* var hmac = CryptoJS . HmacMD5 ( message , key ) ;
* /
C . HmacMD5 = Hasher . _createHmacHelper ( MD5 ) ;
} ( Math ) ) ;
( function ( ) {
// Shortcuts
var C = CryptoJS ;
var C _lib = C . lib ;
var Base = C _lib . Base ;
var WordArray = C _lib . WordArray ;
var C _algo = C . algo ;
var MD5 = C _algo . MD5 ;
/ * *
* This key derivation function is meant to conform with EVP _BytesToKey .
* www . openssl . org / docs / crypto / EVP _BytesToKey . html
* /
var EvpKDF = C _algo . EvpKDF = Base . extend ( {
/ * *
* Configuration options .
*
* @ property { number } keySize The key size in words to generate . Default : 4 ( 128 bits )
* @ property { Hasher } hasher The hash algorithm to use . Default : MD5
* @ property { number } iterations The number of iterations to perform . Default : 1
* /
cfg : Base . extend ( {
keySize : 128 / 32 ,
hasher : MD5 ,
iterations : 1
} ) ,
/ * *
* Initializes a newly created key derivation function .
*
* @ param { Object } cfg ( Optional ) The configuration options to use for the derivation .
*
* @ example
*
* var kdf = CryptoJS . algo . EvpKDF . create ( ) ;
* var kdf = CryptoJS . algo . EvpKDF . create ( { keySize : 8 } ) ;
* var kdf = CryptoJS . algo . EvpKDF . create ( { keySize : 8 , iterations : 1000 } ) ;
* /
init : function ( cfg ) {
this . cfg = this . cfg . extend ( cfg ) ;
} ,
/ * *
* Derives a key from a password .
*
* @ param { WordArray | string } password The password .
* @ param { WordArray | string } salt A salt .
*
* @ return { WordArray } The derived key .
*
* @ example
*
* var key = kdf . compute ( password , salt ) ;
* /
compute : function ( password , salt ) {
// Shortcut
var cfg = this . cfg ;
// Init hasher
var hasher = cfg . hasher . create ( ) ;
// Initial values
var derivedKey = WordArray . create ( ) ;
// Shortcuts
var derivedKeyWords = derivedKey . words ;
var keySize = cfg . keySize ;
var iterations = cfg . iterations ;
// Generate key
while ( derivedKeyWords . length < keySize ) {
if ( block ) {
hasher . update ( block ) ;
}
var block = hasher . update ( password ) . finalize ( salt ) ;
hasher . reset ( ) ;
// Iterations
for ( var i = 1 ; i < iterations ; i ++ ) {
block = hasher . finalize ( block ) ;
hasher . reset ( ) ;
}
derivedKey . concat ( block ) ;
}
derivedKey . sigBytes = keySize * 4 ;
return derivedKey ;
}
} ) ;
/ * *
* Derives a key from a password .
*
* @ param { WordArray | string } password The password .
* @ param { WordArray | string } salt A salt .
* @ param { Object } cfg ( Optional ) The configuration options to use for this computation .
*
* @ return { WordArray } The derived key .
*
* @ static
*
* @ example
*
* var key = CryptoJS . EvpKDF ( password , salt ) ;
* var key = CryptoJS . EvpKDF ( password , salt , { keySize : 8 } ) ;
* var key = CryptoJS . EvpKDF ( password , salt , { keySize : 8 , iterations : 1000 } ) ;
* /
C . EvpKDF = function ( password , salt , cfg ) {
return EvpKDF . create ( cfg ) . compute ( password , salt ) ;
} ;
} ( ) ) ;
/ * *
* Cipher core components .
* /
CryptoJS . lib . Cipher || ( function ( undefined ) {
// Shortcuts
var C = CryptoJS ;
var C _lib = C . lib ;
var Base = C _lib . Base ;
var WordArray = C _lib . WordArray ;
var BufferedBlockAlgorithm = C _lib . BufferedBlockAlgorithm ;
var C _enc = C . enc ;
var Utf8 = C _enc . Utf8 ;
var Base64 = C _enc . Base64 ;
var C _algo = C . algo ;
var EvpKDF = C _algo . EvpKDF ;
/ * *
* Abstract base cipher template .
*
* @ property { number } keySize This cipher ' s key size . Default : 4 ( 128 bits )
* @ property { number } ivSize This cipher ' s IV size . Default : 4 ( 128 bits )
* @ property { number } _ENC _XFORM _MODE A constant representing encryption mode .
* @ property { number } _DEC _XFORM _MODE A constant representing decryption mode .
* /
var Cipher = C _lib . Cipher = BufferedBlockAlgorithm . extend ( {
/ * *
* Configuration options .
*
* @ property { WordArray } iv The IV to use for this operation .
* /
cfg : Base . extend ( ) ,
/ * *
* Creates this cipher in encryption mode .
*
* @ param { WordArray } key The key .
* @ param { Object } cfg ( Optional ) The configuration options to use for this operation .
*
* @ return { Cipher } A cipher instance .
*
* @ static
*
* @ example
*
* var cipher = CryptoJS . algo . AES . createEncryptor ( keyWordArray , { iv : ivWordArray } ) ;
* /
createEncryptor : function ( key , cfg ) {
return this . create ( this . _ENC _XFORM _MODE , key , cfg ) ;
} ,
/ * *
* Creates this cipher in decryption mode .
*
* @ param { WordArray } key The key .
* @ param { Object } cfg ( Optional ) The configuration options to use for this operation .
*
* @ return { Cipher } A cipher instance .
*
* @ static
*
* @ example
*
* var cipher = CryptoJS . algo . AES . createDecryptor ( keyWordArray , { iv : ivWordArray } ) ;
* /
createDecryptor : function ( key , cfg ) {
return this . create ( this . _DEC _XFORM _MODE , key , cfg ) ;
} ,
/ * *
* Initializes a newly created cipher .
*
* @ param { number } xformMode Either the encryption or decryption transormation mode constant .
* @ param { WordArray } key The key .
* @ param { Object } cfg ( Optional ) The configuration options to use for this operation .
*
* @ example
*
* var cipher = CryptoJS . algo . AES . create ( CryptoJS . algo . AES . _ENC _XFORM _MODE , keyWordArray , { iv : ivWordArray } ) ;
* /
init : function ( xformMode , key , cfg ) {
// Apply config defaults
this . cfg = this . cfg . extend ( cfg ) ;
// Store transform mode and key
this . _xformMode = xformMode ;
this . _key = key ;
// Set initial values
this . reset ( ) ;
} ,
/ * *
* Resets this cipher to its initial state .
*
* @ example
*
* cipher . reset ( ) ;
* /
reset : function ( ) {
// Reset data buffer
BufferedBlockAlgorithm . reset . call ( this ) ;
// Perform concrete-cipher logic
this . _doReset ( ) ;
} ,
/ * *
* Adds data to be encrypted or decrypted .
*
* @ param { WordArray | string } dataUpdate The data to encrypt or decrypt .
*
* @ return { WordArray } The data after processing .
*
* @ example
*
* var encrypted = cipher . process ( 'data' ) ;
* var encrypted = cipher . process ( wordArray ) ;
* /
process : function ( dataUpdate ) {
// Append
this . _append ( dataUpdate ) ;
// Process available blocks
return this . _process ( ) ;
} ,
/ * *
* Finalizes the encryption or decryption process .
* Note that the finalize operation is effectively a destructive , read - once operation .
*
* @ param { WordArray | string } dataUpdate The final data to encrypt or decrypt .
*
* @ return { WordArray } The data after final processing .
*
* @ example
*
* var encrypted = cipher . finalize ( ) ;
* var encrypted = cipher . finalize ( 'data' ) ;
* var encrypted = cipher . finalize ( wordArray ) ;
* /
finalize : function ( dataUpdate ) {
// Final data update
if ( dataUpdate ) {
this . _append ( dataUpdate ) ;
}
// Perform concrete-cipher logic
var finalProcessedData = this . _doFinalize ( ) ;
return finalProcessedData ;
} ,
keySize : 128 / 32 ,
ivSize : 128 / 32 ,
_ENC _XFORM _MODE : 1 ,
_DEC _XFORM _MODE : 2 ,
/ * *
* Creates shortcut functions to a cipher ' s object interface .
*
* @ param { Cipher } cipher The cipher to create a helper for .
*
* @ return { Object } An object with encrypt and decrypt shortcut functions .
*
* @ static
*
* @ example
*
* var AES = CryptoJS . lib . Cipher . _createHelper ( CryptoJS . algo . AES ) ;
* /
_createHelper : ( function ( ) {
function selectCipherStrategy ( key ) {
if ( typeof key == 'string' ) {
return PasswordBasedCipher ;
} else {
return SerializableCipher ;
}
}
return function ( cipher ) {
return {
encrypt : function ( message , key , cfg ) {
return selectCipherStrategy ( key ) . encrypt ( cipher , message , key , cfg ) ;
} ,
decrypt : function ( ciphertext , key , cfg ) {
return selectCipherStrategy ( key ) . decrypt ( cipher , ciphertext , key , cfg ) ;
}
} ;
} ;
} ( ) )
} ) ;
/ * *
* Abstract base stream cipher template .
*
* @ property { number } blockSize The number of 32 - bit words this cipher operates on . Default : 1 ( 32 bits )
* /
var StreamCipher = C _lib . StreamCipher = Cipher . extend ( {
_doFinalize : function ( ) {
// Process partial blocks
var finalProcessedBlocks = this . _process ( ! ! 'flush' ) ;
return finalProcessedBlocks ;
} ,
blockSize : 1
} ) ;
/ * *
* Mode namespace .
* /
var C _mode = C . mode = { } ;
/ * *
* Abstract base block cipher mode template .
* /
var BlockCipherMode = C _lib . BlockCipherMode = Base . extend ( {
/ * *
* Creates this mode for encryption .
*
* @ param { Cipher } cipher A block cipher instance .
* @ param { Array } iv The IV words .
*
* @ static
*
* @ example
*
* var mode = CryptoJS . mode . CBC . createEncryptor ( cipher , iv . words ) ;
* /
createEncryptor : function ( cipher , iv ) {
return this . Encryptor . create ( cipher , iv ) ;
} ,
/ * *
* Creates this mode for decryption .
*
* @ param { Cipher } cipher A block cipher instance .
* @ param { Array } iv The IV words .
*
* @ static
*
* @ example
*
* var mode = CryptoJS . mode . CBC . createDecryptor ( cipher , iv . words ) ;
* /
createDecryptor : function ( cipher , iv ) {
return this . Decryptor . create ( cipher , iv ) ;
} ,
/ * *
* Initializes a newly created mode .
*
* @ param { Cipher } cipher A block cipher instance .
* @ param { Array } iv The IV words .
*
* @ example
*
* var mode = CryptoJS . mode . CBC . Encryptor . create ( cipher , iv . words ) ;
* /
init : function ( cipher , iv ) {
this . _cipher = cipher ;
this . _iv = iv ;
}
} ) ;
/ * *
* Cipher Block Chaining mode .
* /
var CBC = C _mode . CBC = ( function ( ) {
/ * *
* Abstract base CBC mode .
* /
var CBC = BlockCipherMode . extend ( ) ;
/ * *
* CBC encryptor .
* /
CBC . Encryptor = CBC . extend ( {
/ * *
* Processes the data block at offset .
*
* @ param { Array } words The data words to operate on .
* @ param { number } offset The offset where the block starts .
*
* @ example
*
* mode . processBlock ( data . words , offset ) ;
* /
processBlock : function ( words , offset ) {
// Shortcuts
var cipher = this . _cipher ;
var blockSize = cipher . blockSize ;
// XOR and encrypt
xorBlock . call ( this , words , offset , blockSize ) ;
cipher . encryptBlock ( words , offset ) ;
// Remember this block to use with next block
this . _prevBlock = words . slice ( offset , offset + blockSize ) ;
}
} ) ;
/ * *
* CBC decryptor .
* /
CBC . Decryptor = CBC . extend ( {
/ * *
* Processes the data block at offset .
*
* @ param { Array } words The data words to operate on .
* @ param { number } offset The offset where the block starts .
*
* @ example
*
* mode . processBlock ( data . words , offset ) ;
* /
processBlock : function ( words , offset ) {
// Shortcuts
var cipher = this . _cipher ;
var blockSize = cipher . blockSize ;
// Remember this block to use with next block
var thisBlock = words . slice ( offset , offset + blockSize ) ;
// Decrypt and XOR
cipher . decryptBlock ( words , offset ) ;
xorBlock . call ( this , words , offset , blockSize ) ;
// This block becomes the previous block
this . _prevBlock = thisBlock ;
}
} ) ;
function xorBlock ( words , offset , blockSize ) {
// Shortcut
var iv = this . _iv ;
// Choose mixing block
if ( iv ) {
var block = iv ;
// Remove IV for subsequent blocks
this . _iv = undefined ;
} else {
var block = this . _prevBlock ;
}
// XOR blocks
for ( var i = 0 ; i < blockSize ; i ++ ) {
words [ offset + i ] ^= block [ i ] ;
}
}
return CBC ;
} ( ) ) ;
/ * *
* Padding namespace .
* /
var C _pad = C . pad = { } ;
/ * *
* PKCS # 5 / 7 padding strategy .
* /
var Pkcs7 = C _pad . Pkcs7 = {
/ * *
* Pads data using the algorithm defined in PKCS # 5 / 7.
*
* @ param { WordArray } data The data to pad .
* @ param { number } blockSize The multiple that the data should be padded to .
*
* @ static
*
* @ example
*
* CryptoJS . pad . Pkcs7 . pad ( wordArray , 4 ) ;
* /
pad : function ( data , blockSize ) {
// Shortcut
var blockSizeBytes = blockSize * 4 ;
// Count padding bytes
var nPaddingBytes = blockSizeBytes - data . sigBytes % blockSizeBytes ;
// Create padding word
var paddingWord = ( nPaddingBytes << 24 ) | ( nPaddingBytes << 16 ) | ( nPaddingBytes << 8 ) | nPaddingBytes ;
// Create padding
var paddingWords = [ ] ;
for ( var i = 0 ; i < nPaddingBytes ; i += 4 ) {
paddingWords . push ( paddingWord ) ;
}
var padding = WordArray . create ( paddingWords , nPaddingBytes ) ;
// Add padding
data . concat ( padding ) ;
} ,
/ * *
* Unpads data that had been padded using the algorithm defined in PKCS # 5 / 7.
*
* @ param { WordArray } data The data to unpad .
*
* @ static
*
* @ example
*
* CryptoJS . pad . Pkcs7 . unpad ( wordArray ) ;
* /
unpad : function ( data ) {
// Get number of padding bytes from last byte
var nPaddingBytes = data . words [ ( data . sigBytes - 1 ) >>> 2 ] & 0xff ;
// Remove padding
data . sigBytes -= nPaddingBytes ;
}
} ;
/ * *
* Abstract base block cipher template .
*
* @ property { number } blockSize The number of 32 - bit words this cipher operates on . Default : 4 ( 128 bits )
* /
var BlockCipher = C _lib . BlockCipher = Cipher . extend ( {
/ * *
* Configuration options .
*
* @ property { Mode } mode The block mode to use . Default : CBC
* @ property { Padding } padding The padding strategy to use . Default : Pkcs7
* /
cfg : Cipher . cfg . extend ( {
mode : CBC ,
padding : Pkcs7
} ) ,
reset : function ( ) {
// Reset cipher
Cipher . reset . call ( this ) ;
// Shortcuts
var cfg = this . cfg ;
var iv = cfg . iv ;
var mode = cfg . mode ;
// Reset block mode
if ( this . _xformMode == this . _ENC _XFORM _MODE ) {
var modeCreator = mode . createEncryptor ;
} else /* if (this._xformMode == this._DEC_XFORM_MODE) */ {
var modeCreator = mode . createDecryptor ;
// Keep at least one block in the buffer for unpadding
this . _minBufferSize = 1 ;
}
this . _mode = modeCreator . call ( mode , this , iv && iv . words ) ;
} ,
_doProcessBlock : function ( words , offset ) {
this . _mode . processBlock ( words , offset ) ;
} ,
_doFinalize : function ( ) {
// Shortcut
var padding = this . cfg . padding ;
// Finalize
if ( this . _xformMode == this . _ENC _XFORM _MODE ) {
// Pad data
padding . pad ( this . _data , this . blockSize ) ;
// Process final blocks
var finalProcessedBlocks = this . _process ( ! ! 'flush' ) ;
} else /* if (this._xformMode == this._DEC_XFORM_MODE) */ {
// Process final blocks
var finalProcessedBlocks = this . _process ( ! ! 'flush' ) ;
// Unpad data
padding . unpad ( finalProcessedBlocks ) ;
}
return finalProcessedBlocks ;
} ,
blockSize : 128 / 32
} ) ;
/ * *
* A collection of cipher parameters .
*
* @ property { WordArray } ciphertext The raw ciphertext .
* @ property { WordArray } key The key to this ciphertext .
* @ property { WordArray } iv The IV used in the ciphering operation .
* @ property { WordArray } salt The salt used with a key derivation function .
* @ property { Cipher } algorithm The cipher algorithm .
* @ property { Mode } mode The block mode used in the ciphering operation .
* @ property { Padding } padding The padding scheme used in the ciphering operation .
* @ property { number } blockSize The block size of the cipher .
* @ property { Format } formatter The default formatting strategy to convert this cipher params object to a string .
* /
var CipherParams = C _lib . CipherParams = Base . extend ( {
/ * *
* Initializes a newly created cipher params object .
*
* @ param { Object } cipherParams An object with any of the possible cipher parameters .
*
* @ example
*
* var cipherParams = CryptoJS . lib . CipherParams . create ( {
* ciphertext : ciphertextWordArray ,
* key : keyWordArray ,
* iv : ivWordArray ,
* salt : saltWordArray ,
* algorithm : CryptoJS . algo . AES ,
* mode : CryptoJS . mode . CBC ,
* padding : CryptoJS . pad . PKCS7 ,
* blockSize : 4 ,
* formatter : CryptoJS . format . OpenSSL
* } ) ;
* /
init : function ( cipherParams ) {
this . mixIn ( cipherParams ) ;
} ,
/ * *
* Converts this cipher params object to a string .
*
* @ param { Format } formatter ( Optional ) The formatting strategy to use .
*
* @ return { string } The stringified cipher params .
*
* @ throws Error If neither the formatter nor the default formatter is set .
*
* @ example
*
* var string = cipherParams + '' ;
* var string = cipherParams . toString ( ) ;
* var string = cipherParams . toString ( CryptoJS . format . OpenSSL ) ;
* /
toString : function ( formatter ) {
return ( formatter || this . formatter ) . stringify ( this ) ;
}
} ) ;
/ * *
* Format namespace .
* /
var C _format = C . format = { } ;
/ * *
* OpenSSL formatting strategy .
* /
var OpenSSLFormatter = C _format . OpenSSL = {
/ * *
* Converts a cipher params object to an OpenSSL - compatible string .
*
* @ param { CipherParams } cipherParams The cipher params object .
*
* @ return { string } The OpenSSL - compatible string .
*
* @ static
*
* @ example
*
* var openSSLString = CryptoJS . format . OpenSSL . stringify ( cipherParams ) ;
* /
stringify : function ( cipherParams ) {
// Shortcuts
var ciphertext = cipherParams . ciphertext ;
var salt = cipherParams . salt ;
// Format
if ( salt ) {
var wordArray = WordArray . create ( [ 0x53616c74 , 0x65645f5f ] ) . concat ( salt ) . concat ( ciphertext ) ;
} else {
var wordArray = ciphertext ;
}
return wordArray . toString ( Base64 ) ;
} ,
/ * *
* Converts an OpenSSL - compatible string to a cipher params object .
*
* @ param { string } openSSLStr The OpenSSL - compatible string .
*
* @ return { CipherParams } The cipher params object .
*
* @ static
*
* @ example
*
* var cipherParams = CryptoJS . format . OpenSSL . parse ( openSSLString ) ;
* /
parse : function ( openSSLStr ) {
// Parse base64
var ciphertext = Base64 . parse ( openSSLStr ) ;
// Shortcut
var ciphertextWords = ciphertext . words ;
// Test for salt
if ( ciphertextWords [ 0 ] == 0x53616c74 && ciphertextWords [ 1 ] == 0x65645f5f ) {
// Extract salt
var salt = WordArray . create ( ciphertextWords . slice ( 2 , 4 ) ) ;
// Remove salt from ciphertext
ciphertextWords . splice ( 0 , 4 ) ;
ciphertext . sigBytes -= 16 ;
}
return CipherParams . create ( { ciphertext : ciphertext , salt : salt } ) ;
}
} ;
/ * *
* A cipher wrapper that returns ciphertext as a serializable cipher params object .
* /
var SerializableCipher = C _lib . SerializableCipher = Base . extend ( {
/ * *
* Configuration options .
*
* @ property { Formatter } format The formatting strategy to convert cipher param objects to and from a string . Default : OpenSSL
* /
cfg : Base . extend ( {
format : OpenSSLFormatter
} ) ,
/ * *
* Encrypts a message .
*
* @ param { Cipher } cipher The cipher algorithm to use .
* @ param { WordArray | string } message The message to encrypt .
* @ param { WordArray } key The key .
* @ param { Object } cfg ( Optional ) The configuration options to use for this operation .
*
* @ return { CipherParams } A cipher params object .
*
* @ static
*
* @ example
*
* var ciphertextParams = CryptoJS . lib . SerializableCipher . encrypt ( CryptoJS . algo . AES , message , key ) ;
* var ciphertextParams = CryptoJS . lib . SerializableCipher . encrypt ( CryptoJS . algo . AES , message , key , { iv : iv } ) ;
* var ciphertextParams = CryptoJS . lib . SerializableCipher . encrypt ( CryptoJS . algo . AES , message , key , { iv : iv , format : CryptoJS . format . OpenSSL } ) ;
* /
encrypt : function ( cipher , message , key , cfg ) {
// Apply config defaults
cfg = this . cfg . extend ( cfg ) ;
// Encrypt
var encryptor = cipher . createEncryptor ( key , cfg ) ;
var ciphertext = encryptor . finalize ( message ) ;
// Shortcut
var cipherCfg = encryptor . cfg ;
// Create and return serializable cipher params
return CipherParams . create ( {
ciphertext : ciphertext ,
key : key ,
iv : cipherCfg . iv ,
algorithm : cipher ,
mode : cipherCfg . mode ,
padding : cipherCfg . padding ,
blockSize : cipher . blockSize ,
formatter : cfg . format
} ) ;
} ,
/ * *
* Decrypts serialized ciphertext .
*
* @ param { Cipher } cipher The cipher algorithm to use .
* @ param { CipherParams | string } ciphertext The ciphertext to decrypt .
* @ param { WordArray } key The key .
* @ param { Object } cfg ( Optional ) The configuration options to use for this operation .
*
* @ return { WordArray } The plaintext .
*
* @ static
*
* @ example
*
* var plaintext = CryptoJS . lib . SerializableCipher . decrypt ( CryptoJS . algo . AES , formattedCiphertext , key , { iv : iv , format : CryptoJS . format . OpenSSL } ) ;
* var plaintext = CryptoJS . lib . SerializableCipher . decrypt ( CryptoJS . algo . AES , ciphertextParams , key , { iv : iv , format : CryptoJS . format . OpenSSL } ) ;
* /
decrypt : function ( cipher , ciphertext , key , cfg ) {
// Apply config defaults
cfg = this . cfg . extend ( cfg ) ;
// Convert string to CipherParams
ciphertext = this . _parse ( ciphertext , cfg . format ) ;
// Decrypt
var plaintext = cipher . createDecryptor ( key , cfg ) . finalize ( ciphertext . ciphertext ) ;
return plaintext ;
} ,
/ * *
* Converts serialized ciphertext to CipherParams ,
* else assumed CipherParams already and returns ciphertext unchanged .
*
* @ param { CipherParams | string } ciphertext The ciphertext .
* @ param { Formatter } format The formatting strategy to use to parse serialized ciphertext .
*
* @ return { CipherParams } The unserialized ciphertext .
*
* @ static
*
* @ example
*
* var ciphertextParams = CryptoJS . lib . SerializableCipher . _parse ( ciphertextStringOrParams , format ) ;
* /
_parse : function ( ciphertext , format ) {
if ( typeof ciphertext == 'string' ) {
return format . parse ( ciphertext , this ) ;
} else {
return ciphertext ;
}
}
} ) ;
/ * *
* Key derivation function namespace .
* /
var C _kdf = C . kdf = { } ;
/ * *
* OpenSSL key derivation function .
* /
var OpenSSLKdf = C _kdf . OpenSSL = {
/ * *
* Derives a key and IV from a password .
*
* @ param { string } password The password to derive from .
* @ param { number } keySize The size in words of the key to generate .
* @ param { number } ivSize The size in words of the IV to generate .
* @ param { WordArray | string } salt ( Optional ) A 64 - bit salt to use . If omitted , a salt will be generated randomly .
*
* @ return { CipherParams } A cipher params object with the key , IV , and salt .
*
* @ static
*
* @ example
*
* var derivedParams = CryptoJS . kdf . OpenSSL . execute ( 'Password' , 256 / 32 , 128 / 32 ) ;
* var derivedParams = CryptoJS . kdf . OpenSSL . execute ( 'Password' , 256 / 32 , 128 / 32 , 'saltsalt' ) ;
* /
execute : function ( password , keySize , ivSize , salt ) {
// Generate random salt
if ( ! salt ) {
salt = WordArray . random ( 64 / 8 ) ;
}
// Derive key and IV
var key = EvpKDF . create ( { keySize : keySize + ivSize } ) . compute ( password , salt ) ;
// Separate key and IV
var iv = WordArray . create ( key . words . slice ( keySize ) , ivSize * 4 ) ;
key . sigBytes = keySize * 4 ;
// Return params
return CipherParams . create ( { key : key , iv : iv , salt : salt } ) ;
}
} ;
/ * *
* A serializable cipher wrapper that derives the key from a password ,
* and returns ciphertext as a serializable cipher params object .
* /
var PasswordBasedCipher = C _lib . PasswordBasedCipher = SerializableCipher . extend ( {
/ * *
* Configuration options .
*
* @ property { KDF } kdf The key derivation function to use to generate a key and IV from a password . Default : OpenSSL
* /
cfg : SerializableCipher . cfg . extend ( {
kdf : OpenSSLKdf
} ) ,
/ * *
* Encrypts a message using a password .
*
* @ param { Cipher } cipher The cipher algorithm to use .
* @ param { WordArray | string } message The message to encrypt .
* @ param { string } password The password .
* @ param { Object } cfg ( Optional ) The configuration options to use for this operation .
*
* @ return { CipherParams } A cipher params object .
*
* @ static
*
* @ example
*
* var ciphertextParams = CryptoJS . lib . PasswordBasedCipher . encrypt ( CryptoJS . algo . AES , message , 'password' ) ;
* var ciphertextParams = CryptoJS . lib . PasswordBasedCipher . encrypt ( CryptoJS . algo . AES , message , 'password' , { format : CryptoJS . format . OpenSSL } ) ;
* /
encrypt : function ( cipher , message , password , cfg ) {
// Apply config defaults
cfg = this . cfg . extend ( cfg ) ;
// Derive key and other params
var derivedParams = cfg . kdf . execute ( password , cipher . keySize , cipher . ivSize ) ;
// Add IV to config
cfg . iv = derivedParams . iv ;
// Encrypt
var ciphertext = SerializableCipher . encrypt . call ( this , cipher , message , derivedParams . key , cfg ) ;
// Mix in derived params
ciphertext . mixIn ( derivedParams ) ;
return ciphertext ;
} ,
/ * *
* Decrypts serialized ciphertext using a password .
*
* @ param { Cipher } cipher The cipher algorithm to use .
* @ param { CipherParams | string } ciphertext The ciphertext to decrypt .
* @ param { string } password The password .
* @ param { Object } cfg ( Optional ) The configuration options to use for this operation .
*
* @ return { WordArray } The plaintext .
*
* @ static
*
* @ example
*
* var plaintext = CryptoJS . lib . PasswordBasedCipher . decrypt ( CryptoJS . algo . AES , formattedCiphertext , 'password' , { format : CryptoJS . format . OpenSSL } ) ;
* var plaintext = CryptoJS . lib . PasswordBasedCipher . decrypt ( CryptoJS . algo . AES , ciphertextParams , 'password' , { format : CryptoJS . format . OpenSSL } ) ;
* /
decrypt : function ( cipher , ciphertext , password , cfg ) {
// Apply config defaults
cfg = this . cfg . extend ( cfg ) ;
// Convert string to CipherParams
ciphertext = this . _parse ( ciphertext , cfg . format ) ;
// Derive key and other params
var derivedParams = cfg . kdf . execute ( password , cipher . keySize , cipher . ivSize , ciphertext . salt ) ;
// Add IV to config
cfg . iv = derivedParams . iv ;
// Decrypt
var plaintext = SerializableCipher . decrypt . call ( this , cipher , ciphertext , derivedParams . key , cfg ) ;
return plaintext ;
}
} ) ;
} ( ) ) ;
( function ( ) {
// Shortcuts
var C = CryptoJS ;
var C _lib = C . lib ;
var BlockCipher = C _lib . BlockCipher ;
var C _algo = C . algo ;
// Lookup tables
var SBOX = [ ] ;
var INV _SBOX = [ ] ;
var SUB _MIX _0 = [ ] ;
var SUB _MIX _1 = [ ] ;
var SUB _MIX _2 = [ ] ;
var SUB _MIX _3 = [ ] ;
var INV _SUB _MIX _0 = [ ] ;
var INV _SUB _MIX _1 = [ ] ;
var INV _SUB _MIX _2 = [ ] ;
var INV _SUB _MIX _3 = [ ] ;
// Compute lookup tables
( function ( ) {
// Compute double table
var d = [ ] ;
for ( var i = 0 ; i < 256 ; i ++ ) {
if ( i < 128 ) {
d [ i ] = i << 1 ;
} else {
d [ i ] = ( i << 1 ) ^ 0x11b ;
}
}
// Walk GF(2^8)
var x = 0 ;
var xi = 0 ;
for ( var i = 0 ; i < 256 ; i ++ ) {
// Compute sbox
var sx = xi ^ ( xi << 1 ) ^ ( xi << 2 ) ^ ( xi << 3 ) ^ ( xi << 4 ) ;
sx = ( sx >>> 8 ) ^ ( sx & 0xff ) ^ 0x63 ;
SBOX [ x ] = sx ;
INV _SBOX [ sx ] = x ;
// Compute multiplication
var x2 = d [ x ] ;
var x4 = d [ x2 ] ;
var x8 = d [ x4 ] ;
// Compute sub bytes, mix columns tables
var t = ( d [ sx ] * 0x101 ) ^ ( sx * 0x1010100 ) ;
SUB _MIX _0 [ x ] = ( t << 24 ) | ( t >>> 8 ) ;
SUB _MIX _1 [ x ] = ( t << 16 ) | ( t >>> 16 ) ;
SUB _MIX _2 [ x ] = ( t << 8 ) | ( t >>> 24 ) ;
SUB _MIX _3 [ x ] = t ;
// Compute inv sub bytes, inv mix columns tables
var t = ( x8 * 0x1010101 ) ^ ( x4 * 0x10001 ) ^ ( x2 * 0x101 ) ^ ( x * 0x1010100 ) ;
INV _SUB _MIX _0 [ sx ] = ( t << 24 ) | ( t >>> 8 ) ;
INV _SUB _MIX _1 [ sx ] = ( t << 16 ) | ( t >>> 16 ) ;
INV _SUB _MIX _2 [ sx ] = ( t << 8 ) | ( t >>> 24 ) ;
INV _SUB _MIX _3 [ sx ] = t ;
// Compute next counter
if ( ! x ) {
x = xi = 1 ;
} else {
x = x2 ^ d [ d [ d [ x8 ^ x2 ] ] ] ;
xi ^= d [ d [ xi ] ] ;
}
}
} ( ) ) ;
// Precomputed Rcon lookup
var RCON = [ 0x00 , 0x01 , 0x02 , 0x04 , 0x08 , 0x10 , 0x20 , 0x40 , 0x80 , 0x1b , 0x36 ] ;
/ * *
* AES block cipher algorithm .
* /
var AES = C _algo . AES = BlockCipher . extend ( {
_doReset : function ( ) {
// Shortcuts
var key = this . _key ;
var keyWords = key . words ;
var keySize = key . sigBytes / 4 ;
// Compute number of rounds
var nRounds = this . _nRounds = keySize + 6
// Compute number of key schedule rows
var ksRows = ( nRounds + 1 ) * 4 ;
// Compute key schedule
var keySchedule = this . _keySchedule = [ ] ;
for ( var ksRow = 0 ; ksRow < ksRows ; ksRow ++ ) {
if ( ksRow < keySize ) {
keySchedule [ ksRow ] = keyWords [ ksRow ] ;
} else {
var t = keySchedule [ ksRow - 1 ] ;
if ( ! ( ksRow % keySize ) ) {
// Rot word
t = ( t << 8 ) | ( t >>> 24 ) ;
// Sub word
t = ( SBOX [ t >>> 24 ] << 24 ) | ( SBOX [ ( t >>> 16 ) & 0xff ] << 16 ) | ( SBOX [ ( t >>> 8 ) & 0xff ] << 8 ) | SBOX [ t & 0xff ] ;
// Mix Rcon
t ^= RCON [ ( ksRow / keySize ) | 0 ] << 24 ;
} else if ( keySize > 6 && ksRow % keySize == 4 ) {
// Sub word
t = ( SBOX [ t >>> 24 ] << 24 ) | ( SBOX [ ( t >>> 16 ) & 0xff ] << 16 ) | ( SBOX [ ( t >>> 8 ) & 0xff ] << 8 ) | SBOX [ t & 0xff ] ;
}
keySchedule [ ksRow ] = keySchedule [ ksRow - keySize ] ^ t ;
}
}
// Compute inv key schedule
var invKeySchedule = this . _invKeySchedule = [ ] ;
for ( var invKsRow = 0 ; invKsRow < ksRows ; invKsRow ++ ) {
var ksRow = ksRows - invKsRow ;
if ( invKsRow % 4 ) {
var t = keySchedule [ ksRow ] ;
} else {
var t = keySchedule [ ksRow - 4 ] ;
}
if ( invKsRow < 4 || ksRow <= 4 ) {
invKeySchedule [ invKsRow ] = t ;
} else {
invKeySchedule [ invKsRow ] = INV _SUB _MIX _0 [ SBOX [ t >>> 24 ] ] ^ INV _SUB _MIX _1 [ SBOX [ ( t >>> 16 ) & 0xff ] ] ^
INV _SUB _MIX _2 [ SBOX [ ( t >>> 8 ) & 0xff ] ] ^ INV _SUB _MIX _3 [ SBOX [ t & 0xff ] ] ;
}
}
} ,
encryptBlock : function ( M , offset ) {
this . _doCryptBlock ( M , offset , this . _keySchedule , SUB _MIX _0 , SUB _MIX _1 , SUB _MIX _2 , SUB _MIX _3 , SBOX ) ;
} ,
decryptBlock : function ( M , offset ) {
// Swap 2nd and 4th rows
var t = M [ offset + 1 ] ;
M [ offset + 1 ] = M [ offset + 3 ] ;
M [ offset + 3 ] = t ;
this . _doCryptBlock ( M , offset , this . _invKeySchedule , INV _SUB _MIX _0 , INV _SUB _MIX _1 , INV _SUB _MIX _2 , INV _SUB _MIX _3 , INV _SBOX ) ;
// Inv swap 2nd and 4th rows
var t = M [ offset + 1 ] ;
M [ offset + 1 ] = M [ offset + 3 ] ;
M [ offset + 3 ] = t ;
} ,
_doCryptBlock : function ( M , offset , keySchedule , SUB _MIX _0 , SUB _MIX _1 , SUB _MIX _2 , SUB _MIX _3 , SBOX ) {
// Shortcut
var nRounds = this . _nRounds ;
// Get input, add round key
var s0 = M [ offset ] ^ keySchedule [ 0 ] ;
var s1 = M [ offset + 1 ] ^ keySchedule [ 1 ] ;
var s2 = M [ offset + 2 ] ^ keySchedule [ 2 ] ;
var s3 = M [ offset + 3 ] ^ keySchedule [ 3 ] ;
// Key schedule row counter
var ksRow = 4 ;
// Rounds
for ( var round = 1 ; round < nRounds ; round ++ ) {
// Shift rows, sub bytes, mix columns, add round key
var t0 = SUB _MIX _0 [ s0 >>> 24 ] ^ SUB _MIX _1 [ ( s1 >>> 16 ) & 0xff ] ^ SUB _MIX _2 [ ( s2 >>> 8 ) & 0xff ] ^ SUB _MIX _3 [ s3 & 0xff ] ^ keySchedule [ ksRow ++ ] ;
var t1 = SUB _MIX _0 [ s1 >>> 24 ] ^ SUB _MIX _1 [ ( s2 >>> 16 ) & 0xff ] ^ SUB _MIX _2 [ ( s3 >>> 8 ) & 0xff ] ^ SUB _MIX _3 [ s0 & 0xff ] ^ keySchedule [ ksRow ++ ] ;
var t2 = SUB _MIX _0 [ s2 >>> 24 ] ^ SUB _MIX _1 [ ( s3 >>> 16 ) & 0xff ] ^ SUB _MIX _2 [ ( s0 >>> 8 ) & 0xff ] ^ SUB _MIX _3 [ s1 & 0xff ] ^ keySchedule [ ksRow ++ ] ;
var t3 = SUB _MIX _0 [ s3 >>> 24 ] ^ SUB _MIX _1 [ ( s0 >>> 16 ) & 0xff ] ^ SUB _MIX _2 [ ( s1 >>> 8 ) & 0xff ] ^ SUB _MIX _3 [ s2 & 0xff ] ^ keySchedule [ ksRow ++ ] ;
// Update state
s0 = t0 ;
s1 = t1 ;
s2 = t2 ;
s3 = t3 ;
}
// Shift rows, sub bytes, add round key
var t0 = ( ( SBOX [ s0 >>> 24 ] << 24 ) | ( SBOX [ ( s1 >>> 16 ) & 0xff ] << 16 ) | ( SBOX [ ( s2 >>> 8 ) & 0xff ] << 8 ) | SBOX [ s3 & 0xff ] ) ^ keySchedule [ ksRow ++ ] ;
var t1 = ( ( SBOX [ s1 >>> 24 ] << 24 ) | ( SBOX [ ( s2 >>> 16 ) & 0xff ] << 16 ) | ( SBOX [ ( s3 >>> 8 ) & 0xff ] << 8 ) | SBOX [ s0 & 0xff ] ) ^ keySchedule [ ksRow ++ ] ;
var t2 = ( ( SBOX [ s2 >>> 24 ] << 24 ) | ( SBOX [ ( s3 >>> 16 ) & 0xff ] << 16 ) | ( SBOX [ ( s0 >>> 8 ) & 0xff ] << 8 ) | SBOX [ s1 & 0xff ] ) ^ keySchedule [ ksRow ++ ] ;
var t3 = ( ( SBOX [ s3 >>> 24 ] << 24 ) | ( SBOX [ ( s0 >>> 16 ) & 0xff ] << 16 ) | ( SBOX [ ( s1 >>> 8 ) & 0xff ] << 8 ) | SBOX [ s2 & 0xff ] ) ^ keySchedule [ ksRow ++ ] ;
// Set output
M [ offset ] = t0 ;
M [ offset + 1 ] = t1 ;
M [ offset + 2 ] = t2 ;
M [ offset + 3 ] = t3 ;
} ,
keySize : 256 / 32
} ) ;
/ * *
* Shortcut functions to the cipher ' s object interface .
*
* @ example
*
* var ciphertext = CryptoJS . AES . encrypt ( message , key , cfg ) ;
* var plaintext = CryptoJS . AES . decrypt ( ciphertext , key , cfg ) ;
* /
C . AES = BlockCipher . _createHelper ( AES ) ;
} ( ) ) ;
/ *
* This program is free software : you can redistribute it and / or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation , either version 3 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU Lesser General Public License for more details .
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program . If not , see < http : //www.gnu.org/licenses/>.
* /
; ( function ( ) {
'use strict' ;
// Test for webcrypto support, polyfill if needed.
if ( window . crypto . subtle === undefined || window . crypto . subtle === null ) {
window . crypto . subtle = ( function ( ) {
var StaticArrayBufferProto = new ArrayBuffer ( ) . _ _proto _ _ ;
function assertIsArrayBuffer ( thing ) {
if ( thing !== Object ( thing ) || thing . _ _proto _ _ != StaticArrayBufferProto )
throw new Error ( "Needed a ArrayBuffer" ) ;
}
// Synchronous implementation functions for polyfilling webcrypto
// All inputs/outputs are arraybuffers!
function HmacSHA256 ( key , input ) {
assertIsArrayBuffer ( key ) ;
assertIsArrayBuffer ( input ) ;
return CryptoJS . HmacSHA256 (
CryptoJS . enc . Latin1 . parse ( getString ( input ) ) ,
CryptoJS . enc . Latin1 . parse ( getString ( key ) )
) ;
} ;
function encryptAESCBC ( plaintext , key , iv ) {
assertIsArrayBuffer ( plaintext ) ;
assertIsArrayBuffer ( key ) ;
assertIsArrayBuffer ( iv ) ;
return CryptoJS . AES . encrypt (
CryptoJS . enc . Latin1 . parse ( getString ( plaintext ) ) ,
CryptoJS . enc . Latin1 . parse ( getString ( key ) ) ,
{ iv : CryptoJS . enc . Latin1 . parse ( getString ( iv ) ) }
) . ciphertext ;
} ;
function decryptAESCBC ( ciphertext , key , iv ) {
assertIsArrayBuffer ( ciphertext ) ;
assertIsArrayBuffer ( key ) ;
assertIsArrayBuffer ( iv ) ;
return CryptoJS . AES . decrypt (
btoa ( getString ( ciphertext ) ) ,
CryptoJS . enc . Latin1 . parse ( getString ( key ) ) ,
{ iv : CryptoJS . enc . Latin1 . parse ( getString ( iv ) ) }
) ;
} ;
// utility function for connecting front and back ends via promises
// Takes an implementation function and 0 or more arguments
function promise ( implementation ) {
var args = Array . prototype . slice . call ( arguments ) ;
args . shift ( ) ;
return new Promise ( function ( resolve ) {
var wordArray = implementation . apply ( this , args ) ;
// convert 32bit WordArray to array buffer
var buffer = new ArrayBuffer ( wordArray . sigBytes ) ;
var view = new DataView ( buffer ) ;
for ( var i = 0 ; i * 4 < buffer . byteLength ; i ++ ) {
view . setInt32 ( i * 4 , wordArray . words [ i ] ) ;
}
resolve ( buffer ) ;
} ) ;
} ;
return {
encrypt : function ( algorithm , key , data ) {
if ( algorithm . name === "AES-CBC" )
return promise ( encryptAESCBC , data , key , algorithm . iv . buffer || algorithm . iv ) ;
} ,
decrypt : function ( algorithm , key , data ) {
if ( algorithm . name === "AES-CBC" )
return promise ( decryptAESCBC , data , key , algorithm . iv . buffer || algorithm . iv ) ;
} ,
sign : function ( algorithm , key , data ) {
if ( algorithm . name === "HMAC" && algorithm . hash === "SHA-256" )
return promise ( HmacSHA256 , key , data ) ;
} ,
importKey : function ( format , key , algorithm , extractable , usages ) {
return new Promise ( function ( resolve , reject ) { resolve ( key ) ; } ) ;
}
} ;
} ) ( ) ;
} // if !window.crypto.subtle
} ) ( ) ;
} ) ( ) ;
2015-01-13 14:09:32 -10:00
; ( function ( ) {
function loadProtoBufs ( filename ) {
return dcodeIO . ProtoBuf . loadProtoFile ( { root : 'protos' , file : filename } ) . build ( 'textsecure' ) ;
} ;
var pushMessages = loadProtoBufs ( 'IncomingPushMessageSignal.proto' ) ;
var protocolMessages = loadProtoBufs ( 'WhisperTextProtocol.proto' ) ;
var subProtocolMessages = loadProtoBufs ( 'SubProtocol.proto' ) ;
var deviceMessages = loadProtoBufs ( 'DeviceMessages.proto' ) ;
window . textsecure = window . textsecure || { } ;
window . textsecure . protobuf = {
IncomingPushMessageSignal : pushMessages . IncomingPushMessageSignal ,
PushMessageContent : pushMessages . PushMessageContent ,
WhisperMessage : protocolMessages . WhisperMessage ,
PreKeyWhisperMessage : protocolMessages . PreKeyWhisperMessage ,
2015-01-19 10:23:25 -10:00
ProvisioningUuid : deviceMessages . ProvisioningUuid ,
2015-01-23 11:19:29 -10:00
ProvisionEnvelope : deviceMessages . ProvisionEnvelope ,
ProvisionMessage : deviceMessages . ProvisionMessage ,
2015-01-13 14:09:32 -10:00
DeviceControl : deviceMessages . DeviceControl ,
WebSocketResponseMessage : subProtocolMessages . WebSocketResponseMessage ,
WebSocketRequestMessage : subProtocolMessages . WebSocketRequestMessage ,
WebSocketMessage : subProtocolMessages . WebSocketMessage
} ;
} ) ( ) ;
/ * v i m : t s = 4 : s w = 4 : e x p a n d t a b
*
* This program is free software : you can redistribute it and / or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation , either version 3 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU Lesser General Public License for more details .
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program . If not , see < http : //www.gnu.org/licenses/>.
* /
; ( function ( ) {
'use strict' ;
/ *
* var socket = textsecure . websocket ( url ) ;
*
* Returns an adamantium - reinforced super socket , capable of sending
* app - level keep alives and automatically reconnecting .
*
* /
window . textsecure . websocket = function ( url ) {
var socketWrapper = {
onmessage : function ( ) { } ,
ondisconnect : function ( ) { } ,
} ;
var socket ;
var keepAliveTimer ;
var reconnectSemaphore = 0 ;
var reconnectTimeout = 1000 ;
function resetKeepAliveTimer ( ) {
clearTimeout ( keepAliveTimer ) ;
keepAliveTimer = setTimeout ( function ( ) {
socket . send (
new textsecure . protobuf . WebSocketMessage ( {
type : textsecure . protobuf . WebSocketMessage . Type . REQUEST ,
request : { verb : 'GET' , path : '/v1/keepalive' }
} ) . encode ( ) . toArrayBuffer ( )
) ;
resetKeepAliveTimer ( ) ;
} , 15000 ) ;
} ;
function reconnect ( e ) {
reconnectSemaphore -- ;
setTimeout ( connect , reconnectTimeout ) ;
socketWrapper . ondisconnect ( e ) ;
} ;
function connect ( ) {
clearTimeout ( keepAliveTimer ) ;
if ( ++ reconnectSemaphore <= 0 ) { return ; }
if ( socket ) { socket . close ( ) ; }
socket = new WebSocket ( url ) ;
socket . onerror = reconnect ;
socket . onclose = reconnect ;
socket . onopen = resetKeepAliveTimer ;
socket . onmessage = function ( response ) {
socketWrapper . onmessage ( response ) ;
resetKeepAliveTimer ( ) ;
} ;
socketWrapper . send = function ( msg ) {
socket . send ( msg ) ;
}
}
connect ( ) ;
return socketWrapper ;
} ;
} ) ( ) ;
/ * v i m : t s = 4 : s w = 4 : e x p a n d t a b
*
* This program is free software : you can redistribute it and / or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation , either version 3 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU Lesser General Public License for more details .
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program . If not , see < http : //www.gnu.org/licenses/>.
* /
; ( function ( ) {
'use strict' ;
/ *
* WebSocket - Resources
*
* Create a request - response interface over websockets using the
* WebSocket - Resources sub - protocol [ 1 ] .
*
* var client = new WebSocketResource ( socket , function ( request ) {
* request . respond ( 200 , 'OK' ) ;
* } ) ;
*
* client . sendRequest ( {
* verb : 'PUT' ,
* path : '/v1/messages' ,
* body : '{ some: "json" }' ,
* success : function ( message , status , request ) { ... } ,
* error : function ( message , status , request ) { ... }
* } ) ;
*
* 1. https : //github.com/WhisperSystems/WebSocket-Resources
*
* /
var Request = function ( options ) {
this . verb = options . verb || options . type ;
this . path = options . path || options . url ;
this . body = options . body || options . data ;
this . success = options . success
this . error = options . error
this . id = options . id ;
if ( this . id === undefined ) {
var bits = new Uint32Array ( 2 ) ;
window . crypto . getRandomValues ( bits ) ;
this . id = dcodeIO . Long . fromBits ( bits [ 0 ] , bits [ 1 ] , true ) ;
}
} ;
var IncomingWebSocketRequest = function ( options ) {
var request = new Request ( options ) ;
var socket = options . socket ;
this . verb = request . verb ;
this . path = request . path ;
this . body = request . body ;
this . respond = function ( status , message ) {
socket . send (
new textsecure . protobuf . WebSocketMessage ( {
type : textsecure . protobuf . WebSocketMessage . Type . RESPONSE ,
response : { id : request . id , message : message , status : status }
} ) . encode ( ) . toArrayBuffer ( )
) ;
} ;
} ;
var outgoing = { } ;
var OutgoingWebSocketRequest = function ( options , socket ) {
var request = new Request ( options ) ;
outgoing [ request . id ] = request ;
socket . send (
new textsecure . protobuf . WebSocketMessage ( {
type : textsecure . protobuf . WebSocketMessage . Type . REQUEST ,
request : {
verb : request . verb ,
path : request . path ,
body : request . body ,
id : request . id
}
} ) . encode ( ) . toArrayBuffer ( )
) ;
} ;
window . WebSocketResource = function ( socket , handleRequest ) {
this . sendRequest = function ( options ) {
return new OutgoingWebSocketRequest ( options , socket ) ;
} ;
socket . onmessage = function ( socketMessage ) {
var blob = socketMessage . data ;
var reader = new FileReader ( ) ;
reader . onload = function ( ) {
var message = textsecure . protobuf . WebSocketMessage . decode ( reader . result ) ;
if ( message . type === textsecure . protobuf . WebSocketMessage . Type . REQUEST ) {
handleRequest (
new IncomingWebSocketRequest ( {
verb : message . request . verb ,
path : message . request . path ,
body : message . request . body ,
id : message . request . id ,
socket : socket
} )
) ;
}
else if ( message . type === textsecure . protobuf . WebSocketMessage . Type . RESPONSE ) {
var response = message . response ;
var request = outgoing [ response . id ] ;
if ( request ) {
request . response = response ;
var callback = request . error ;
if ( response . status >= 200 && response . status < 300 ) {
callback = request . success ;
}
if ( typeof callback === 'function' ) {
callback ( response . message , response . status , request ) ;
}
} else {
throw 'Received response for unknown request ' + message . response . id ;
}
}
} ;
reader . readAsArrayBuffer ( blob ) ;
} ;
} ;
} ( ) ) ;
/ * v i m : t s = 4 : s w = 4 : e x p a n d t a b
*
* This program is free software : you can redistribute it and / or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation , either version 3 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU Lesser General Public License for more details .
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program . If not , see < http : //www.gnu.org/licenses/>.
* /
window . textsecure = window . textsecure || { } ;
/ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* * * Type conversion utilities * * *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * /
// Strings/arrays
//TODO: Throw all this shit in favor of consistent types
//TODO: Namespace
var StaticByteBufferProto = new dcodeIO . ByteBuffer ( ) . _ _proto _ _ ;
var StaticArrayBufferProto = new ArrayBuffer ( ) . _ _proto _ _ ;
var StaticUint8ArrayProto = new Uint8Array ( ) . _ _proto _ _ ;
function getString ( thing ) {
if ( thing === Object ( thing ) ) {
if ( thing . _ _proto _ _ == StaticUint8ArrayProto )
return String . fromCharCode . apply ( null , thing ) ;
if ( thing . _ _proto _ _ == StaticArrayBufferProto )
return getString ( new Uint8Array ( thing ) ) ;
if ( thing . _ _proto _ _ == StaticByteBufferProto )
return thing . toString ( "binary" ) ;
}
return thing ;
}
function getStringable ( thing ) {
return ( typeof thing == "string" || typeof thing == "number" || typeof thing == "boolean" ||
( thing === Object ( thing ) &&
( thing . _ _proto _ _ == StaticArrayBufferProto ||
thing . _ _proto _ _ == StaticUint8ArrayProto ||
thing . _ _proto _ _ == StaticByteBufferProto ) ) ) ;
}
function isEqual ( a , b , mayBeShort ) {
// TODO: Special-case arraybuffers, etc
if ( a === undefined || b === undefined )
return false ;
a = getString ( a ) ;
b = getString ( b ) ;
var maxLength = mayBeShort ? Math . min ( a . length , b . length ) : Math . max ( a . length , b . length ) ;
if ( maxLength < 5 )
throw new Error ( "a/b compare too short" ) ;
return a . substring ( 0 , Math . min ( maxLength , a . length ) ) == b . substring ( 0 , Math . min ( maxLength , b . length ) ) ;
}
function toArrayBuffer ( thing ) {
//TODO: Optimize this for specific cases
if ( thing === undefined )
return undefined ;
if ( thing === Object ( thing ) && thing . _ _proto _ _ == StaticArrayBufferProto )
return thing ;
if ( thing instanceof Array ) {
// Assuming Uint16Array from curve25519
var res = new ArrayBuffer ( thing . length * 2 ) ;
var uint = new Uint16Array ( res ) ;
for ( var i = 0 ; i < thing . length ; i ++ )
uint [ i ] = thing [ i ] ;
return res ;
}
if ( ! getStringable ( thing ) )
throw new Error ( "Tried to convert a non-stringable thing of type " + typeof thing + " to an array buffer" ) ;
var str = getString ( thing ) ;
var res = new ArrayBuffer ( str . length ) ;
var uint = new Uint8Array ( res ) ;
for ( var i = 0 ; i < str . length ; i ++ )
uint [ i ] = str . charCodeAt ( i ) ;
return res ;
}
// Number formatting utils
window . textsecure . utils = function ( ) {
var self = { } ;
self . unencodeNumber = function ( number ) {
return number . split ( "." ) ;
} ;
self . isNumberSane = function ( number ) {
return number [ 0 ] == "+" &&
/^[0-9]+$/ . test ( number . substring ( 1 ) ) ;
}
/ * * * * * * * * * * * * * * * * * * * * * * * * * *
* * * JSON ' ing Utilities * * *
* * * * * * * * * * * * * * * * * * * * * * * * * * /
function ensureStringed ( thing ) {
if ( getStringable ( thing ) )
return getString ( thing ) ;
else if ( thing instanceof Array ) {
var res = [ ] ;
for ( var i = 0 ; i < thing . length ; i ++ )
res [ i ] = ensureStringed ( thing [ i ] ) ;
return res ;
} else if ( thing === Object ( thing ) ) {
var res = { } ;
for ( var key in thing )
res [ key ] = ensureStringed ( thing [ key ] ) ;
return res ;
}
throw new Error ( "unsure of how to jsonify object of type " + typeof thing ) ;
}
self . jsonThing = function ( thing ) {
return JSON . stringify ( ensureStringed ( thing ) ) ;
}
return self ;
} ( ) ;
window . textsecure . throwHumanError = function ( error , type , humanError ) {
var e = new Error ( error ) ;
if ( type !== undefined )
e . name = type ;
e . humanError = humanError ;
throw e ;
}
var handleAttachment = function ( attachment ) {
function getAttachment ( ) {
return textsecure . api . getAttachment ( attachment . id . toString ( ) ) ;
}
function decryptAttachment ( encrypted ) {
return textsecure . protocol . decryptAttachment (
encrypted ,
attachment . key . toArrayBuffer ( )
) ;
}
function updateAttachment ( data ) {
attachment . data = data ;
}
return getAttachment ( ) .
then ( decryptAttachment ) .
then ( updateAttachment ) ;
} ;
textsecure . processDecrypted = function ( decrypted , source ) {
// Now that its decrypted, validate the message and clean it up for consumer processing
// Note that messages may (generally) only perform one action and we ignore remaining fields
// after the first action.
if ( decrypted . flags == null )
decrypted . flags = 0 ;
if ( ( decrypted . flags & textsecure . protobuf . PushMessageContent . Flags . END _SESSION )
== textsecure . protobuf . PushMessageContent . Flags . END _SESSION )
return ;
if ( decrypted . flags != 0 ) {
throw new Error ( "Unknown flags in message" ) ;
}
var promises = [ ] ;
if ( decrypted . group !== null ) {
decrypted . group . id = getString ( decrypted . group . id ) ;
var existingGroup = textsecure . storage . groups . getNumbers ( decrypted . group . id ) ;
if ( existingGroup === undefined ) {
if ( decrypted . group . type != textsecure . protobuf . PushMessageContent . GroupContext . Type . UPDATE ) {
throw new Error ( "Got message for unknown group" ) ;
}
textsecure . storage . groups . createNewGroup ( decrypted . group . members , decrypted . group . id ) ;
if ( decrypted . group . avatar !== null ) {
promises . push ( handleAttachment ( decrypted . group . avatar ) ) ;
}
} else {
var fromIndex = existingGroup . indexOf ( source ) ;
if ( fromIndex < 0 ) {
//TODO: This could be indication of a race...
throw new Error ( "Sender was not a member of the group they were sending from" ) ;
}
switch ( decrypted . group . type ) {
case textsecure . protobuf . PushMessageContent . GroupContext . Type . UPDATE :
if ( decrypted . group . avatar !== null )
promises . push ( handleAttachment ( decrypted . group . avatar ) ) ;
if ( decrypted . group . members . filter ( function ( number ) { return ! textsecure . utils . isNumberSane ( number ) ; } ) . length != 0 )
throw new Error ( "Invalid number in new group members" ) ;
if ( existingGroup . filter ( function ( number ) { decrypted . group . members . indexOf ( number ) < 0 } ) . length != 0 )
throw new Error ( "Attempted to remove numbers from group with an UPDATE" ) ;
decrypted . group . added = decrypted . group . members . filter ( function ( number ) { return existingGroup . indexOf ( number ) < 0 ; } ) ;
var newGroup = textsecure . storage . groups . addNumbers ( decrypted . group . id , decrypted . group . added ) ;
if ( newGroup . length != decrypted . group . members . length ||
newGroup . filter ( function ( number ) { return decrypted . group . members . indexOf ( number ) < 0 ; } ) . length != 0 ) {
throw new Error ( "Error calculating group member difference" ) ;
}
//TODO: Also follow this path if avatar + name haven't changed (ie we should start storing those)
if ( decrypted . group . avatar === null && decrypted . group . added . length == 0 && decrypted . group . name === null ) {
return ;
}
decrypted . body = null ;
decrypted . attachments = [ ] ;
break ;
case textsecure . protobuf . PushMessageContent . GroupContext . Type . QUIT :
textsecure . storage . groups . removeNumber ( decrypted . group . id , source ) ;
decrypted . body = null ;
decrypted . attachments = [ ] ;
case textsecure . protobuf . PushMessageContent . GroupContext . Type . DELIVER :
decrypted . group . name = null ;
decrypted . group . members = [ ] ;
decrypted . group . avatar = null ;
break ;
default :
throw new Error ( "Unknown group message type" ) ;
}
}
}
for ( var i in decrypted . attachments ) {
promises . push ( handleAttachment ( decrypted . attachments [ i ] ) ) ;
}
return Promise . all ( promises ) . then ( function ( ) {
return decrypted ;
} ) ;
}
window . textsecure . registerSingleDevice = function ( number , verificationCode , stepDone ) {
var signalingKey = textsecure . crypto . getRandomBytes ( 32 + 20 ) ;
textsecure . storage . putEncrypted ( 'signaling_key' , signalingKey ) ;
var password = btoa ( getString ( textsecure . crypto . getRandomBytes ( 16 ) ) ) ;
password = password . substring ( 0 , password . length - 2 ) ;
textsecure . storage . putEncrypted ( "password" , password ) ;
var registrationId = new Uint16Array ( textsecure . crypto . getRandomBytes ( 2 ) ) [ 0 ] ;
registrationId = registrationId & 0x3fff ;
textsecure . storage . putUnencrypted ( "registrationId" , registrationId ) ;
return textsecure . api . confirmCode ( number , verificationCode , password , signalingKey , registrationId , true ) . then ( function ( ) {
var numberId = number + ".1" ;
textsecure . storage . putUnencrypted ( "number_id" , numberId ) ;
textsecure . storage . putUnencrypted ( "regionCode" , libphonenumber . util . getRegionCodeForNumber ( number ) ) ;
stepDone ( 1 ) ;
return textsecure . protocol . generateKeys ( ) . then ( function ( keys ) {
stepDone ( 2 ) ;
return textsecure . api . registerKeys ( keys ) . then ( function ( ) {
stepDone ( 3 ) ;
} ) ;
} ) ;
} ) ;
}
2015-01-23 11:19:29 -10:00
window . textsecure . registerSecondDevice = function ( encodedProvisionEnvelope , cryptoInfo , stepDone ) {
var envelope = textsecure . protobuf . ProvisionEnvelope . decode ( encodedProvisionEnvelope , 'binary' ) ;
return cryptoInfo . decryptAndHandleDeviceInit ( envelope ) . then ( function ( identityKey ) {
2015-01-13 14:09:32 -10:00
stepDone ( 1 ) ;
var signalingKey = textsecure . crypto . getRandomBytes ( 32 + 20 ) ;
textsecure . storage . putEncrypted ( 'signaling_key' , signalingKey ) ;
var password = btoa ( getString ( textsecure . crypto . getRandomBytes ( 16 ) ) ) ;
password = password . substring ( 0 , password . length - 2 ) ;
textsecure . storage . putEncrypted ( "password" , password ) ;
var registrationId = new Uint16Array ( textsecure . crypto . getRandomBytes ( 2 ) ) [ 0 ] ;
registrationId = registrationId & 0x3fff ;
textsecure . storage . putUnencrypted ( "registrationId" , registrationId ) ;
2015-01-23 11:19:29 -10:00
return textsecure . api . confirmCode ( identityKey . number , identityKey . provisioningCode , password , signalingKey , registrationId , false ) . then ( function ( result ) {
var numberId = identityKey . number + "." + result . deviceId ;
2015-01-13 14:09:32 -10:00
textsecure . storage . putUnencrypted ( "number_id" , numberId ) ;
2015-01-23 11:19:29 -10:00
textsecure . storage . putUnencrypted ( "regionCode" , libphonenumber . util . getRegionCodeForNumber ( identityKey . number ) ) ;
2015-01-13 14:09:32 -10:00
stepDone ( 2 ) ;
return textsecure . protocol . generateKeys ( ) . then ( function ( keys ) {
stepDone ( 3 ) ;
return textsecure . api . registerKeys ( keys ) . then ( function ( ) {
stepDone ( 4 ) ;
} ) ;
} ) ;
} ) ;
} ) ;
} ;
/ * v i m : t s = 4 : s w = 4 : e x p a n d t a b
*
* This program is free software : you can redistribute it and / or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation , either version 3 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU Lesser General Public License for more details .
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program . If not , see < http : //www.gnu.org/licenses/>.
* /
; ( function ( ) {
'use strict' ;
var registeredFunctions = { } ;
var Type = {
SEND _MESSAGE : 1 ,
INIT _SESSION : 2 ,
} ;
window . textsecure = window . textsecure || { } ;
window . textsecure . replay = {
Type : Type ,
registerFunction : function ( func , functionCode ) {
registeredFunctions [ functionCode ] = func ;
}
} ;
function ReplayableError ( options ) {
options = options || { } ;
this . name = options . name || 'ReplayableError' ;
this . functionCode = options . functionCode ;
this . args = options . args ;
}
ReplayableError . prototype = new Error ( ) ;
ReplayableError . prototype . constructor = ReplayableError ;
ReplayableError . prototype . replay = function ( ) {
var args = Array . prototype . slice . call ( arguments ) ;
args . shift ( ) ;
args = this . args . concat ( args ) ;
registeredFunctions [ this . functionCode ] . apply ( window , args ) ;
} ;
function IncomingIdentityKeyError ( number , message ) {
ReplayableError . call ( this , {
functionCode : Type . INIT _SESSION ,
args : [ number , message ]
} ) ;
this . name = 'IncomingIdentityKeyError' ;
this . message = "The identity of the sender has changed. This may be malicious, or the sender may have simply reinstalled TextSecure." ;
}
IncomingIdentityKeyError . prototype = new ReplayableError ( ) ;
IncomingIdentityKeyError . prototype . constructor = IncomingIdentityKeyError ;
function OutgoingIdentityKeyError ( number , message ) {
ReplayableError . call ( this , {
functionCode : Type . SEND _MESSAGE ,
args : [ number , message ]
} ) ;
this . name = 'OutgoingIdentityKeyError' ;
this . message = "The identity of the destination has changed. This may be malicious, or the destination may have simply reinstalled TextSecure." ;
}
OutgoingIdentityKeyError . prototype = new ReplayableError ( ) ;
OutgoingIdentityKeyError . prototype . constructor = OutgoingIdentityKeyError ;
window . textsecure . IncomingIdentityKeyError = IncomingIdentityKeyError ;
window . textsecure . OutgoingIdentityKeyError = OutgoingIdentityKeyError ;
window . textsecure . ReplayableError = ReplayableError ;
} ) ( ) ;
/ * v i m : t s = 4 : s w = 4 : e x p a n d t a b
*
* This program is free software : you can redistribute it and / or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation , either version 3 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU Lesser General Public License for more details .
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program . If not , see < http : //www.gnu.org/licenses/>.
* /
; ( function ( ) {
"use strict" ;
window . StringView = {
/ *
* These functions from the Mozilla Developer Network
* and have been placed in the public domain .
* https : //developer.mozilla.org/en-US/docs/Web/API/WindowBase64/Base64_encoding_and_decoding
* https : //developer.mozilla.org/en-US/docs/MDN/About#Copyrights_and_licenses
* /
b64ToUint6 : function ( nChr ) {
return nChr > 64 && nChr < 91 ?
nChr - 65
: nChr > 96 && nChr < 123 ?
nChr - 71
: nChr > 47 && nChr < 58 ?
nChr + 4
: nChr === 43 ?
62
: nChr === 47 ?
63
:
0 ;
} ,
base64ToBytes : function ( sBase64 , nBlocksSize ) {
var
sB64Enc = sBase64 . replace ( /[^A-Za-z0-9\+\/]/g , "" ) , nInLen = sB64Enc . length ,
nOutLen = nBlocksSize ? Math . ceil ( ( nInLen * 3 + 1 >> 2 ) / nBlocksSize ) * nBlocksSize : nInLen * 3 + 1 >> 2 ;
var aBBytes = new ArrayBuffer ( nOutLen ) ;
var taBytes = new Uint8Array ( aBBytes ) ;
for ( var nMod3 , nMod4 , nUint24 = 0 , nOutIdx = 0 , nInIdx = 0 ; nInIdx < nInLen ; nInIdx ++ ) {
nMod4 = nInIdx & 3 ;
nUint24 |= StringView . b64ToUint6 ( sB64Enc . charCodeAt ( nInIdx ) ) << 18 - 6 * nMod4 ;
if ( nMod4 === 3 || nInLen - nInIdx === 1 ) {
for ( nMod3 = 0 ; nMod3 < 3 && nOutIdx < nOutLen ; nMod3 ++ , nOutIdx ++ ) {
taBytes [ nOutIdx ] = nUint24 >>> ( 16 >>> nMod3 & 24 ) & 255 ;
}
nUint24 = 0 ;
}
}
return aBBytes ;
} ,
uint6ToB64 : function ( nUint6 ) {
return nUint6 < 26 ?
nUint6 + 65
: nUint6 < 52 ?
nUint6 + 71
: nUint6 < 62 ?
nUint6 - 4
: nUint6 === 62 ?
43
: nUint6 === 63 ?
47
:
65 ;
} ,
bytesToBase64 : function ( aBytes ) {
var nMod3 , sB64Enc = "" ;
for ( var nLen = aBytes . length , nUint24 = 0 , nIdx = 0 ; nIdx < nLen ; nIdx ++ ) {
nMod3 = nIdx % 3 ;
if ( nIdx > 0 && ( nIdx * 4 / 3 ) % 76 === 0 ) { sB64Enc += "\r\n" ; }
nUint24 |= aBytes [ nIdx ] << ( 16 >>> nMod3 & 24 ) ;
if ( nMod3 === 2 || aBytes . length - nIdx === 1 ) {
sB64Enc += String . fromCharCode (
StringView . uint6ToB64 ( nUint24 >>> 18 & 63 ) ,
StringView . uint6ToB64 ( nUint24 >>> 12 & 63 ) ,
StringView . uint6ToB64 ( nUint24 >>> 6 & 63 ) ,
StringView . uint6ToB64 ( nUint24 & 63 )
) ;
nUint24 = 0 ;
}
}
return sB64Enc . replace ( /A(?=A$|$)/g , "=" ) ;
}
} ;
} ( ) ) ;
/ * v i m : t s = 4 : s w = 4
*
* This program is free software : you can redistribute it and / or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation , either version 3 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU Lesser General Public License for more details .
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program . If not , see < http : //www.gnu.org/licenses/>.
* /
'use strict' ;
; ( function ( ) {
/ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* * * Utilities to store data in local storage * * *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * /
window . textsecure = window . textsecure || { } ;
window . textsecure . storage = window . textsecure . storage || { } ;
window . textsecure . storage = {
/ * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* * * Base Storage Routines * * *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * /
putEncrypted : function ( key , value ) {
//TODO
if ( value === undefined )
throw new Error ( "Tried to store undefined" ) ;
localStorage . setItem ( "e" + key , textsecure . utils . jsonThing ( value ) ) ;
} ,
getEncrypted : function ( key , defaultValue ) {
//TODO
var value = localStorage . getItem ( "e" + key ) ;
if ( value === null )
return defaultValue ;
return JSON . parse ( value ) ;
} ,
removeEncrypted : function ( key ) {
localStorage . removeItem ( "e" + key ) ;
} ,
putUnencrypted : function ( key , value ) {
if ( value === undefined )
throw new Error ( "Tried to store undefined" ) ;
localStorage . setItem ( "u" + key , textsecure . utils . jsonThing ( value ) ) ;
} ,
getUnencrypted : function ( key , defaultValue ) {
var value = localStorage . getItem ( "u" + key ) ;
if ( value === null )
return defaultValue ;
return JSON . parse ( value ) ;
} ,
removeUnencrypted : function ( key ) {
localStorage . removeItem ( "u" + key ) ;
}
} ;
} ) ( ) ;
/ * v i m : t s = 4 : s w = 4
*
* This program is free software : you can redistribute it and / or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation , either version 3 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU Lesser General Public License for more details .
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program . If not , see < http : //www.gnu.org/licenses/>.
* /
'use strict' ;
; ( function ( ) {
/ * * * * * * * * * * * * * * * * * * * * * *
* * * Device Storage * * *
* * * * * * * * * * * * * * * * * * * * * * /
window . textsecure = window . textsecure || { } ;
window . textsecure . storage = window . textsecure . storage || { } ;
window . textsecure . storage . devices = {
saveDeviceObject : function ( deviceObject ) {
return internalSaveDeviceObject ( deviceObject , false ) ;
} ,
saveKeysToDeviceObject : function ( deviceObject ) {
return internalSaveDeviceObject ( deviceObject , true ) ;
} ,
getDeviceObjectsForNumber : function ( number ) {
var map = textsecure . storage . getEncrypted ( "devices" + number ) ;
return map === undefined ? [ ] : map . devices ;
} ,
getDeviceObject : function ( encodedNumber ) {
var number = textsecure . utils . unencodeNumber ( encodedNumber ) ;
var devices = textsecure . storage . devices . getDeviceObjectsForNumber ( number [ 0 ] ) ;
if ( devices === undefined )
return undefined ;
for ( var i in devices )
if ( devices [ i ] . encodedNumber == encodedNumber )
return devices [ i ] ;
return undefined ;
} ,
removeDeviceIdsForNumber : function ( number , deviceIdsToRemove ) {
var map = textsecure . storage . getEncrypted ( "devices" + number ) ;
if ( map === undefined )
throw new Error ( "Tried to remove device for unknown number" ) ;
var newDevices = [ ] ;
var devicesRemoved = 0 ;
for ( var i in map . devices ) {
var keep = true ;
for ( var j in deviceIdsToRemove )
if ( map . devices [ i ] . encodedNumber == number + "." + deviceIdsToRemove [ j ] )
keep = false ;
if ( keep )
newDevices . push ( map . devices [ i ] ) ;
else
devicesRemoved ++ ;
}
if ( devicesRemoved != deviceIdsToRemove . length )
throw new Error ( "Tried to remove unknown device" ) ;
}
} ;
var internalSaveDeviceObject = function ( deviceObject , onlyKeys ) {
if ( deviceObject . identityKey === undefined || deviceObject . encodedNumber === undefined )
throw new Error ( "Tried to store invalid deviceObject" ) ;
var number = textsecure . utils . unencodeNumber ( deviceObject . encodedNumber ) [ 0 ] ;
var map = textsecure . storage . getEncrypted ( "devices" + number ) ;
if ( map === undefined )
map = { devices : [ deviceObject ] , identityKey : deviceObject . identityKey } ;
else if ( map . identityKey != getString ( deviceObject . identityKey ) )
throw new Error ( "Identity key changed" ) ;
else {
var updated = false ;
for ( var i in map . devices ) {
if ( map . devices [ i ] . encodedNumber == deviceObject . encodedNumber ) {
if ( ! onlyKeys )
map . devices [ i ] = deviceObject ;
else {
map . devices [ i ] . preKey = deviceObject . preKey ;
map . devices [ i ] . preKeyId = deviceObject . preKeyId ;
map . devices [ i ] . signedKey = deviceObject . signedKey ;
map . devices [ i ] . signedKeyId = deviceObject . signedKeyId ;
map . devices [ i ] . registrationId = deviceObject . registrationId ;
}
updated = true ;
}
}
if ( ! updated )
map . devices . push ( deviceObject ) ;
}
textsecure . storage . putEncrypted ( "devices" + number , map ) ;
} ;
} ) ( ) ;
/ * v i m : t s = 4 : s w = 4
*
* This program is free software : you can redistribute it and / or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation , either version 3 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU Lesser General Public License for more details .
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program . If not , see < http : //www.gnu.org/licenses/>.
* /
'use strict' ;
; ( function ( ) {
/ * * * * * * * * * * * * * * * * * * * * *
* * * Group Storage * * *
* * * * * * * * * * * * * * * * * * * * * /
window . textsecure = window . textsecure || { } ;
window . textsecure . storage = window . textsecure . storage || { } ;
window . textsecure . storage . groups = {
createNewGroup : function ( numbers , groupId ) {
2015-01-14 11:24:45 -10:00
if ( groupId !== undefined && textsecure . storage . getEncrypted ( "group" + groupId ) !== undefined )
2015-01-13 14:09:32 -10:00
throw new Error ( "Tried to recreate group" ) ;
2015-01-14 11:24:45 -10:00
while ( groupId === undefined || textsecure . storage . getEncrypted ( "group" + groupId ) !== undefined )
2015-01-13 14:09:32 -10:00
groupId = getString ( textsecure . crypto . getRandomBytes ( 16 ) ) ;
var me = textsecure . utils . unencodeNumber ( textsecure . storage . getUnencrypted ( "number_id" ) ) [ 0 ] ;
var haveMe = false ;
var finalNumbers = [ ] ;
for ( var i in numbers ) {
var number = numbers [ i ] ;
if ( ! textsecure . utils . isNumberSane ( number ) )
throw new Error ( "Invalid number in group" ) ;
if ( number == me )
haveMe = true ;
2015-01-14 11:24:45 -10:00
if ( finalNumbers . indexOf ( number ) < 0 )
2015-01-13 14:09:32 -10:00
finalNumbers . push ( number ) ;
}
if ( ! haveMe )
finalNumbers . push ( me ) ;
2015-01-14 11:24:45 -10:00
var groupObject = { numbers : finalNumbers , numberRegistrationIds : { } } ;
for ( var i in finalNumbers )
groupObject . numberRegistrationIds [ finalNumbers [ i ] ] = { } ;
textsecure . storage . putEncrypted ( "group" + groupId , groupObject ) ;
2015-01-13 14:09:32 -10:00
return { id : groupId , numbers : finalNumbers } ;
} ,
getNumbers : function ( groupId ) {
var group = textsecure . storage . getEncrypted ( "group" + groupId ) ;
if ( group === undefined )
return undefined ;
return group . numbers ;
} ,
removeNumber : function ( groupId , number ) {
var group = textsecure . storage . getEncrypted ( "group" + groupId ) ;
if ( group === undefined )
return undefined ;
var me = textsecure . utils . unencodeNumber ( textsecure . storage . getUnencrypted ( "number_id" ) ) [ 0 ] ;
if ( number == me )
throw new Error ( "Cannot remove ourselves from a group, leave the group instead" ) ;
var i = group . numbers . indexOf ( number ) ;
if ( i > - 1 ) {
group . numbers . slice ( i , 1 ) ;
2015-01-14 11:24:45 -10:00
delete group . numberRegistrationIds [ number ] ;
2015-01-13 14:09:32 -10:00
textsecure . storage . putEncrypted ( "group" + groupId , group ) ;
}
return group . numbers ;
} ,
addNumbers : function ( groupId , numbers ) {
var group = textsecure . storage . getEncrypted ( "group" + groupId ) ;
if ( group === undefined )
return undefined ;
for ( var i in numbers ) {
var number = numbers [ i ] ;
if ( ! textsecure . utils . isNumberSane ( number ) )
throw new Error ( "Invalid number in set to add to group" ) ;
if ( group . numbers . indexOf ( number ) < 0 ) {
group . numbers . push ( number ) ;
2015-01-14 11:24:45 -10:00
group . numberRegistrationIds [ number ] = { } ;
2015-01-13 14:09:32 -10:00
}
}
textsecure . storage . putEncrypted ( "group" + groupId , group ) ;
return group . numbers ;
} ,
deleteGroup : function ( groupId ) {
textsecure . storage . removeEncrypted ( "group" + groupId ) ;
} ,
getGroup : function ( groupId ) {
var group = textsecure . storage . getEncrypted ( "group" + groupId ) ;
if ( group === undefined )
return undefined ;
return { id : groupId , numbers : group . numbers } ; //TODO: avatar/name tracking
2015-01-14 11:24:45 -10:00
} ,
2015-01-13 14:09:32 -10:00
2015-01-14 11:24:45 -10:00
needUpdateByDeviceRegistrationId : function ( groupId , number , encodedNumber , registrationId ) {
var group = textsecure . storage . getEncrypted ( "group" + groupId ) ;
if ( group === undefined )
throw new Error ( "Unknown group for device registration id" ) ;
2015-01-13 14:09:32 -10:00
2015-01-14 11:24:45 -10:00
if ( group . numberRegistrationIds [ number ] === undefined )
throw new Error ( "Unknown number in group for device registration id" ) ;
if ( group . numberRegistrationIds [ number ] [ encodedNumber ] == registrationId )
return false ;
var needUpdate = group . numberRegistrationIds [ number ] [ encodedNumber ] !== undefined ;
group . numberRegistrationIds [ number ] [ encodedNumber ] = registrationId ;
textsecure . storage . putEncrypted ( "group" + groupId , group ) ;
return needUpdate ;
} ,
} ;
2015-01-13 14:09:32 -10:00
} ) ( ) ;
/ * v i m : t s = 4 : s w = 4 : e x p a n d t a b
*
* This program is free software : you can redistribute it and / or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation , either version 3 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU Lesser General Public License for more details .
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program . If not , see < http : //www.gnu.org/licenses/>.
* /
window . textsecure = window . textsecure || { } ;
window . textsecure . api = function ( ) {
'use strict' ;
var self = { } ;
/ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* * * Utilities to communicate with the server * * *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * /
// Staging server
var URL _BASE = "https://textsecure-service-staging.whispersystems.org" ;
self . relay = "textsecure-service-staging.whispersystems.org" ;
var ATTACHMENT _HOST = "whispersystems-textsecure-attachments-staging.s3.amazonaws.com" ;
// This is the real server
//var URL_BASE = "https://textsecure-service.whispersystems.org";
var URL _CALLS = { } ;
URL _CALLS . accounts = "/v1/accounts" ;
URL _CALLS . devices = "/v1/devices" ;
URL _CALLS . keys = "/v2/keys" ;
URL _CALLS . push = "/v1/websocket" ;
2015-01-23 11:19:29 -10:00
URL _CALLS . temp _push = "/v1/websocket/provisioning" ;
2015-01-13 14:09:32 -10:00
URL _CALLS . messages = "/v1/messages" ;
URL _CALLS . attachment = "/v1/attachments" ;
/ * *
* REQUIRED PARAMS :
* call : URL _CALLS entry
* httpType : POST / GET / PUT / etc
* OPTIONAL PARAMS :
* success _callback : function ( response object ) called on success
* error _callback : function ( http status code = - 1 or != 200 ) called on failure
* urlParameters : crap appended to the url ( probably including a leading / )
* user : user name to be sent in a basic auth header
* password : password to be sent in a basic auth headerA
* do _auth : alternative to user / password where user / password are figured out automagically
* jsonData : JSON data sent in the request body
* /
var doAjax = function ( param ) {
if ( param . urlParameters === undefined ) {
param . urlParameters = "" ;
}
if ( param . do _auth ) {
param . user = textsecure . storage . getUnencrypted ( "number_id" ) ;
param . password = textsecure . storage . getEncrypted ( "password" ) ;
}
return new Promise ( function ( resolve , reject ) {
$ . ajax ( URL _BASE + URL _CALLS [ param . call ] + param . urlParameters , {
type : param . httpType ,
data : param . jsonData && textsecure . utils . jsonThing ( param . jsonData ) ,
contentType : 'application/json; charset=utf-8' ,
dataType : 'json' ,
beforeSend : function ( xhr ) {
if ( param . user !== undefined &&
param . password !== undefined )
xhr . setRequestHeader ( "Authorization" , "Basic " + btoa ( getString ( param . user ) + ":" + getString ( param . password ) ) ) ;
} ,
success : function ( response , textStatus , jqXHR ) {
resolve ( response ) ;
} ,
error : function ( jqXHR , textStatus , errorThrown ) {
var code = jqXHR . status ;
if ( code === 200 ) {
// happens sometimes when we get no response
// (TODO: Fix server to return 204? instead)
resolve ( null ) ;
return ;
}
if ( code > 999 || code < 100 )
code = - 1 ;
try {
switch ( code ) {
case - 1 :
textsecure . throwHumanError ( code , "HTTPError" ,
"Failed to connect to the server, please check your network connection." ) ;
case 413 :
textsecure . throwHumanError ( code , "HTTPError" ,
"Rate limit exceeded, please try again later." ) ;
case 403 :
textsecure . throwHumanError ( code , "HTTPError" ,
"Invalid code, please try again." ) ;
case 417 :
// TODO: This shouldn't be a thing?, but its in the API doc?
textsecure . throwHumanError ( code , "HTTPError" ,
"Number already registered." ) ;
case 401 :
textsecure . throwHumanError ( code , "HTTPError" ,
"Invalid authentication, most likely someone re-registered and invalidated our registration." ) ;
case 404 :
textsecure . throwHumanError ( code , "HTTPError" ,
"Number is not registered with TextSecure." ) ;
default :
textsecure . throwHumanError ( code , "HTTPError" ,
"The server rejected our query, please file a bug report." ) ;
}
} catch ( e ) {
if ( jqXHR . responseJSON )
e . response = jqXHR . responseJSON ;
reject ( e ) ;
}
}
} ) ;
} ) ;
} ;
function requestVerificationCode ( number , transport ) {
return doAjax ( {
call : 'accounts' ,
httpType : 'GET' ,
urlParameters : '/' + transport + '/code/' + number ,
} ) ;
} ;
self . requestVerificationSMS = function ( number ) {
return requestVerificationCode ( number , 'sms' ) ;
} ;
self . requestVerificationVoice = function ( number ) {
return requestVerificationCode ( number , 'voice' ) ;
} ;
self . confirmCode = function ( number , code , password ,
signaling _key , registrationId , single _device ) {
var call = single _device ? 'accounts' : 'devices' ;
var urlPrefix = single _device ? '/code/' : '/' ;
return doAjax ( {
call : call ,
httpType : 'PUT' ,
urlParameters : urlPrefix + code ,
user : number ,
password : password ,
jsonData : { signalingKey : btoa ( getString ( signaling _key ) ) ,
supportsSms : false ,
fetchesMessages : true ,
registrationId : registrationId }
} ) ;
} ;
self . registerKeys = function ( genKeys ) {
var keys = { } ;
keys . identityKey = btoa ( getString ( genKeys . identityKey ) ) ;
keys . signedPreKey = { keyId : genKeys . signedPreKey . keyId , publicKey : btoa ( getString ( genKeys . signedPreKey . publicKey ) ) ,
signature : btoa ( getString ( genKeys . signedPreKey . signature ) ) } ;
keys . preKeys = [ ] ;
var j = 0 ;
for ( var i in genKeys . preKeys )
keys . preKeys [ j ++ ] = { keyId : i , publicKey : btoa ( getString ( genKeys . preKeys [ i ] . publicKey ) ) } ;
//TODO: This is just to make the server happy (v2 clients should choke on publicKey),
// it needs removed before release
keys . lastResortKey = { keyId : 0x7fffFFFF , publicKey : btoa ( "42" ) } ;
return doAjax ( {
call : 'keys' ,
httpType : 'PUT' ,
do _auth : true ,
jsonData : keys ,
} ) ;
} ;
self . getKeysForNumber = function ( number , deviceId ) {
if ( deviceId === undefined )
deviceId = "*" ;
return doAjax ( {
call : 'keys' ,
httpType : 'GET' ,
do _auth : true ,
urlParameters : "/" + number + "/" + deviceId ,
} ) . then ( function ( res ) {
var promises = [ ] ;
res . identityKey = StringView . base64ToBytes ( res . identityKey ) ;
for ( var i = 0 ; i < res . devices . length ; i ++ ) {
res . devices [ i ] . signedPreKey . publicKey = StringView . base64ToBytes ( res . devices [ i ] . signedPreKey . publicKey ) ;
res . devices [ i ] . signedPreKey . signature = StringView . base64ToBytes ( res . devices [ i ] . signedPreKey . signature ) ;
promises [ i ] = window . textsecure . crypto . Ed25519Verify ( res . identityKey , res . devices [ i ] . signedPreKey . publicKey , res . devices [ i ] . signedPreKey . signature ) ;
res . devices [ i ] . preKey . publicKey = StringView . base64ToBytes ( res . devices [ i ] . preKey . publicKey ) ;
//TODO: Is this still needed?
//if (res.devices[i].keyId === undefined)
// res.devices[i].keyId = 0;
}
return Promise . all ( promises ) . then ( function ( ) {
return res ;
} ) ;
} ) ;
} ;
self . sendMessages = function ( destination , messageArray ) {
//TODO: Do this conversion somewhere else?
for ( var i = 0 ; i < messageArray . length ; i ++ )
messageArray [ i ] . body = btoa ( messageArray [ i ] . body ) ;
var jsonData = { messages : messageArray } ;
if ( messageArray [ 0 ] . relay !== undefined )
jsonData . relay = messageArray [ 0 ] . relay ;
jsonData . timestamp = messageArray [ 0 ] . timestamp ;
return doAjax ( {
call : 'messages' ,
httpType : 'PUT' ,
urlParameters : '/' + destination ,
do _auth : true ,
jsonData : jsonData ,
} ) ;
} ;
self . getAttachment = function ( id ) {
return doAjax ( {
call : 'attachment' ,
httpType : 'GET' ,
urlParameters : '/' + id ,
do _auth : true ,
} ) . then ( function ( response ) {
return new Promise ( function ( resolve , reject ) {
$ . ajax ( response . location , {
type : "GET" ,
xhrFields : {
responseType : "arraybuffer"
} ,
headers : {
"Content-Type" : "application/octet-stream"
} ,
success : function ( response , textStatus , jqXHR ) {
resolve ( response ) ;
} ,
error : function ( jqXHR , textStatus , errorThrown ) {
var code = jqXHR . status ;
if ( code > 999 || code < 100 )
code = - 1 ;
var e = new Error ( code ) ;
e . name = "HTTPError" ;
if ( jqXHR . responseJSON )
e . response = jqXHR . responseJSON ;
reject ( e ) ;
}
} ) ;
} ) ;
} ) ;
} ;
var id _regex = RegExp ( "^https:\/\/" + ATTACHMENT _HOST + "\/(\\d+)\?" ) ;
self . putAttachment = function ( encryptedBin ) {
return doAjax ( {
call : 'attachment' ,
httpType : 'GET' ,
do _auth : true ,
} ) . then ( function ( response ) {
return new Promise ( function ( resolve , reject ) {
$ . ajax ( response . location , {
type : "PUT" ,
headers : { "Content-Type" : "application/octet-stream" } ,
data : encryptedBin ,
processData : false ,
success : function ( ) {
try {
// Parse the id as a string from the location url
// (workaround for ids too large for Javascript numbers)
var id = response . location . match ( id _regex ) [ 1 ] ;
resolve ( id ) ;
} catch ( e ) {
reject ( e ) ;
}
} ,
error : function ( jqXHR , textStatus , errorThrown ) {
var code = jqXHR . status ;
if ( code > 999 || code < 100 )
code = - 1 ;
var e = new Error ( code ) ;
e . name = "HTTPError" ;
if ( jqXHR . responseJSON )
e . response = jqXHR . responseJSON ;
reject ( e ) ;
}
} ) ;
} ) ;
} ) ;
} ;
var getWebsocket = function ( url , auth , reconnectTimeout ) {
var URL = URL _BASE . replace ( /^http/g , 'ws' ) + url + '/?' ;
var params = '' ;
if ( auth ) {
var user = textsecure . storage . getUnencrypted ( "number_id" ) ;
var password = textsecure . storage . getEncrypted ( "password" ) ;
var params = $ . param ( {
login : '+' + user . substring ( 1 ) ,
password : password
} ) ;
}
return window . textsecure . websocket ( URL + params )
}
self . getMessageWebsocket = function ( ) {
return getWebsocket ( URL _CALLS [ 'push' ] , true , 1000 ) ;
}
self . getTempWebsocket = function ( ) {
2015-01-19 10:23:25 -10:00
return getWebsocket ( URL _CALLS [ 'temp_push' ] , false , 1000 ) ;
2015-01-13 14:09:32 -10:00
}
return self ;
} ( ) ;
/ * v i m : t s = 4 : s w = 4
*
* This program is free software : you can redistribute it and / or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation , either version 3 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU Lesser General Public License for more details .
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program . If not , see < http : //www.gnu.org/licenses/>.
* /
; ( function ( ) {
window . textsecure = window . textsecure || { } ;
/ *
* textsecure . crypto
* glues together various implementations into a single interface
* for all low - level crypto operations ,
* /
window . textsecure . crypto = {
getRandomBytes : function ( size ) {
// At some point we might consider XORing in hashes of random
// UI events to strengthen ourselves against RNG flaws in crypto.getRandomValues
// ie maybe take a look at how Gibson does it at https://www.grc.com/r&d/js.htm
var array = new Uint8Array ( size ) ;
window . crypto . getRandomValues ( array ) ;
return array . buffer ;
} ,
encrypt : function ( key , data , iv ) {
return window . crypto . subtle . importKey ( 'raw' , key , { name : 'AES-CBC' } , false , [ 'encrypt' ] ) . then ( function ( key ) {
return window . crypto . subtle . encrypt ( { name : 'AES-CBC' , iv : new Uint8Array ( iv ) } , key , data ) ;
} ) ;
} ,
decrypt : function ( key , data , iv ) {
return window . crypto . subtle . importKey ( 'raw' , key , { name : 'AES-CBC' } , false , [ 'decrypt' ] ) . then ( function ( key ) {
return window . crypto . subtle . decrypt ( { name : 'AES-CBC' , iv : new Uint8Array ( iv ) } , key , data ) ;
} ) ;
} ,
sign : function ( key , data ) {
return window . crypto . subtle . importKey ( 'raw' , key , { name : 'HMAC' , hash : { name : 'SHA-256' } } , false , [ 'sign' ] ) . then ( function ( key ) {
return window . crypto . subtle . sign ( { name : 'HMAC' , hash : 'SHA-256' } , key , data ) ;
} ) ;
} ,
HKDF : function ( input , salt , info ) {
// Specific implementation of RFC 5869 that only returns the first 3 32-byte chunks
// TODO: We dont always need the third chunk, we might skip it
return window . textsecure . crypto . sign ( salt , input ) . then ( function ( PRK ) {
var infoBuffer = new ArrayBuffer ( info . byteLength + 1 + 32 ) ;
var infoArray = new Uint8Array ( infoBuffer ) ;
infoArray . set ( new Uint8Array ( info ) , 32 ) ;
infoArray [ infoArray . length - 1 ] = 1 ;
return window . textsecure . crypto . sign ( PRK , infoBuffer . slice ( 32 ) ) . then ( function ( T1 ) {
infoArray . set ( new Uint8Array ( T1 ) ) ;
infoArray [ infoArray . length - 1 ] = 2 ;
return window . textsecure . crypto . sign ( PRK , infoBuffer ) . then ( function ( T2 ) {
infoArray . set ( new Uint8Array ( T2 ) ) ;
infoArray [ infoArray . length - 1 ] = 3 ;
return window . textsecure . crypto . sign ( PRK , infoBuffer ) . then ( function ( T3 ) {
return [ T1 , T2 , T3 ] ;
} ) ;
} ) ;
} ) ;
} ) ;
} ,
// Curve 25519 crypto
createKeyPair : function ( privKey ) {
if ( privKey === undefined ) {
privKey = textsecure . crypto . getRandomBytes ( 32 ) ;
}
if ( privKey . byteLength != 32 ) {
throw new Error ( "Invalid private key" ) ;
}
2015-01-14 11:24:45 -10:00
return window . curve25519 . keyPair ( privKey ) . then ( function ( raw _keys ) {
2015-01-13 14:09:32 -10:00
// prepend version byte
var origPub = new Uint8Array ( raw _keys . pubKey ) ;
var pub = new Uint8Array ( 33 ) ;
pub . set ( origPub , 1 ) ;
pub [ 0 ] = 5 ;
return { pubKey : pub . buffer , privKey : raw _keys . privKey } ;
} ) ;
} ,
ECDHE : function ( pubKey , privKey ) {
pubKey = validatePubKeyFormat ( pubKey ) ;
if ( privKey === undefined || privKey . byteLength != 32 )
throw new Error ( "Invalid private key" ) ;
if ( pubKey === undefined || pubKey . byteLength != 32 )
throw new Error ( "Invalid public key" ) ;
2015-01-14 11:24:45 -10:00
return window . curve25519 . sharedSecret ( pubKey , privKey ) ;
2015-01-13 14:09:32 -10:00
} ,
Ed25519Sign : function ( privKey , message ) {
if ( privKey === undefined || privKey . byteLength != 32 )
throw new Error ( "Invalid private key" ) ;
if ( message === undefined )
throw new Error ( "Invalid message" ) ;
2015-01-14 11:24:45 -10:00
return window . curve25519 . sign ( privKey , message ) ;
2015-01-13 14:09:32 -10:00
} ,
Ed25519Verify : function ( pubKey , msg , sig ) {
pubKey = validatePubKeyFormat ( pubKey ) ;
if ( pubKey === undefined || pubKey . byteLength != 32 )
throw new Error ( "Invalid public key" ) ;
if ( msg === undefined )
throw new Error ( "Invalid message" ) ;
if ( sig === undefined || sig . byteLength != 64 )
throw new Error ( "Invalid signature" ) ;
2015-01-14 11:24:45 -10:00
return window . curve25519 . verify ( pubKey , msg , sig ) ;
2015-01-13 14:09:32 -10:00
}
} ;
var validatePubKeyFormat = function ( pubKey ) {
if ( pubKey === undefined || ( ( pubKey . byteLength != 33 || new Uint8Array ( pubKey ) [ 0 ] != 5 ) && pubKey . byteLength != 32 ) )
throw new Error ( "Invalid public key" ) ;
if ( pubKey . byteLength == 33 ) {
return pubKey . slice ( 1 ) ;
} else {
console . error ( "WARNING: Expected pubkey of length 33, please report the ST and client that generated the pubkey" ) ;
return pubKey ;
}
} ;
} ) ( ) ;
/ * v i m : t s = 4 : s w = 4
*
* This program is free software : you can redistribute it and / or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation , either version 3 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU Lesser General Public License for more details .
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program . If not , see < http : //www.gnu.org/licenses/>.
* /
; ( function ( ) {
'use strict' ;
window . textsecure = window . textsecure || { } ;
window . textsecure . protocol = function ( ) {
var self = { } ;
/ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* * * Random constants / utils * * *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * /
// We consider messages lost after a week and might throw away keys at that point
// (also the time between signedPreKey regenerations)
var MESSAGE _LOST _THRESHOLD _MS = 1000 * 60 * 60 * 24 * 7 ;
function objectContainsKeys ( object ) {
var count = 0 ;
for ( var key in object ) {
count ++ ;
break ;
}
return count != 0 ;
}
/ * * * * * * * * * * * * * * * * * * * * * * * * * * *
* * * Key / session storage * * *
* * * * * * * * * * * * * * * * * * * * * * * * * * * /
var crypto _storage = { } ;
crypto _storage . putKeyPair = function ( keyName , keyPair ) {
textsecure . storage . putEncrypted ( "25519Key" + keyName , keyPair ) ;
}
crypto _storage . getNewStoredKeyPair = function ( keyName ) {
return textsecure . crypto . createKeyPair ( ) . then ( function ( keyPair ) {
crypto _storage . putKeyPair ( keyName , keyPair ) ;
return keyPair ;
} ) ;
}
crypto _storage . getStoredKeyPair = function ( keyName ) {
var res = textsecure . storage . getEncrypted ( "25519Key" + keyName ) ;
if ( res === undefined )
return undefined ;
return { pubKey : toArrayBuffer ( res . pubKey ) , privKey : toArrayBuffer ( res . privKey ) } ;
}
crypto _storage . removeStoredKeyPair = function ( keyName ) {
textsecure . storage . removeEncrypted ( "25519Key" + keyName ) ;
}
crypto _storage . getIdentityKey = function ( ) {
return this . getStoredKeyPair ( "identityKey" ) ;
}
crypto _storage . saveSession = function ( encodedNumber , session , registrationId ) {
var device = textsecure . storage . devices . getDeviceObject ( encodedNumber ) ;
if ( device === undefined )
device = { sessions : { } , encodedNumber : encodedNumber } ;
if ( registrationId !== undefined )
device . registrationId = registrationId ;
crypto _storage . saveSessionAndDevice ( device , session ) ;
}
crypto _storage . saveSessionAndDevice = function ( device , session ) {
if ( device . sessions === undefined )
device . sessions = { } ;
var sessions = device . sessions ;
var doDeleteSession = false ;
if ( session . indexInfo . closed == - 1 || device . identityKey === undefined )
device . identityKey = session . indexInfo . remoteIdentityKey ;
if ( session . indexInfo . closed != - 1 ) {
doDeleteSession = ( session . indexInfo . closed < ( new Date ( ) . getTime ( ) - MESSAGE _LOST _THRESHOLD _MS ) ) ;
if ( ! doDeleteSession ) {
var keysLeft = false ;
for ( var key in session ) {
if ( key != "indexInfo" && key != "oldRatchetList" && key != "currentRatchet" ) {
keysLeft = true ;
break ;
}
}
doDeleteSession = ! keysLeft ;
console . log ( ( doDeleteSession ? "Deleting " : "Not deleting " ) + "closed session which has not yet timed out" ) ;
} else
console . log ( "Deleting closed session due to timeout (created at " + session . indexInfo . closed + ")" ) ;
}
if ( doDeleteSession )
delete sessions [ getString ( session . indexInfo . baseKey ) ] ;
else
sessions [ getString ( session . indexInfo . baseKey ) ] = session ;
var openSessionRemaining = false ;
for ( var key in sessions )
if ( sessions [ key ] . indexInfo . closed == - 1 )
openSessionRemaining = true ;
if ( ! openSessionRemaining )
try {
delete device [ 'registrationId' ] ;
} catch ( _ ) { }
textsecure . storage . devices . saveDeviceObject ( device ) ;
}
var getSessions = function ( encodedNumber ) {
var device = textsecure . storage . devices . getDeviceObject ( encodedNumber ) ;
if ( device === undefined || device . sessions === undefined )
return undefined ;
return device . sessions ;
}
crypto _storage . getOpenSession = function ( encodedNumber ) {
var sessions = getSessions ( encodedNumber ) ;
if ( sessions === undefined )
return undefined ;
for ( var key in sessions )
if ( sessions [ key ] . indexInfo . closed == - 1 )
return sessions [ key ] ;
return undefined ;
}
crypto _storage . getSessionByRemoteEphemeralKey = function ( encodedNumber , remoteEphemeralKey ) {
var sessions = getSessions ( encodedNumber ) ;
if ( sessions === undefined )
return undefined ;
var searchKey = getString ( remoteEphemeralKey ) ;
var openSession = undefined ;
for ( var key in sessions ) {
if ( sessions [ key ] . indexInfo . closed == - 1 ) {
if ( openSession !== undefined )
throw new Error ( "Datastore inconsistensy: multiple open sessions for " + encodedNumber ) ;
openSession = sessions [ key ] ;
}
if ( sessions [ key ] [ searchKey ] !== undefined )
return sessions [ key ] ;
}
if ( openSession !== undefined )
return openSession ;
return undefined ;
}
crypto _storage . getSessionOrIdentityKeyByBaseKey = function ( encodedNumber , baseKey ) {
var sessions = getSessions ( encodedNumber ) ;
var device = textsecure . storage . devices . getDeviceObject ( encodedNumber ) ;
if ( device === undefined )
return undefined ;
var preferredSession = device . sessions && device . sessions [ getString ( baseKey ) ] ;
if ( preferredSession !== undefined )
return preferredSession ;
if ( device . identityKey !== undefined )
return { indexInfo : { remoteIdentityKey : device . identityKey } } ;
throw new Error ( "Datastore inconsistency: device was stored without identity key" ) ;
}
/ * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* * * Internal Crypto stuff * * *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * /
var HKDF = function ( input , salt , info ) {
// HKDF for TextSecure has a bit of additional handling - salts always end up being 32 bytes
if ( salt == '' )
salt = new ArrayBuffer ( 32 ) ;
if ( salt . byteLength != 32 )
throw new Error ( "Got salt of incorrect length" ) ;
info = toArrayBuffer ( info ) ; // TODO: maybe convert calls?
return textsecure . crypto . HKDF ( input , salt , info ) ;
}
var verifyMAC = function ( data , key , mac ) {
return textsecure . crypto . sign ( key , data ) . then ( function ( calculated _mac ) {
if ( ! isEqual ( calculated _mac , mac , true ) )
throw new Error ( "Bad MAC" ) ;
} ) ;
}
/ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* * * Ratchet implementation * * *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * /
var calculateRatchet = function ( session , remoteKey , sending ) {
var ratchet = session . currentRatchet ;
return textsecure . crypto . ECDHE ( remoteKey , toArrayBuffer ( ratchet . ephemeralKeyPair . privKey ) ) . then ( function ( sharedSecret ) {
return HKDF ( sharedSecret , toArrayBuffer ( ratchet . rootKey ) , "WhisperRatchet" ) . then ( function ( masterKey ) {
if ( sending )
session [ getString ( ratchet . ephemeralKeyPair . pubKey ) ] = { messageKeys : { } , chainKey : { counter : - 1 , key : masterKey [ 1 ] } } ;
else
session [ getString ( remoteKey ) ] = { messageKeys : { } , chainKey : { counter : - 1 , key : masterKey [ 1 ] } } ;
ratchet . rootKey = masterKey [ 0 ] ;
} ) ;
} ) ;
}
var initSession = function ( isInitiator , ourEphemeralKey , ourSignedKey , encodedNumber , theirIdentityPubKey , theirEphemeralPubKey , theirSignedPubKey ) {
var ourIdentityKey = crypto _storage . getIdentityKey ( ) ;
if ( isInitiator ) {
if ( ourSignedKey !== undefined )
throw new Error ( "Invalid call to initSession" ) ;
ourSignedKey = ourEphemeralKey ;
} else {
if ( theirSignedPubKey !== undefined )
throw new Error ( "Invalid call to initSession" ) ;
theirSignedPubKey = theirEphemeralPubKey ;
}
var sharedSecret ;
if ( ourEphemeralKey === undefined || theirEphemeralPubKey === undefined )
sharedSecret = new Uint8Array ( 32 * 4 ) ;
else
sharedSecret = new Uint8Array ( 32 * 5 ) ;
for ( var i = 0 ; i < 32 ; i ++ )
sharedSecret [ i ] = 0xff ;
return textsecure . crypto . ECDHE ( theirSignedPubKey , ourIdentityKey . privKey ) . then ( function ( ecRes1 ) {
function finishInit ( ) {
return textsecure . crypto . ECDHE ( theirSignedPubKey , ourSignedKey . privKey ) . then ( function ( ecRes ) {
sharedSecret . set ( new Uint8Array ( ecRes ) , 32 * 3 ) ;
return HKDF ( sharedSecret . buffer , '' , "WhisperText" ) . then ( function ( masterKey ) {
var session = { currentRatchet : { rootKey : masterKey [ 0 ] , lastRemoteEphemeralKey : theirSignedPubKey , previousCounter : 0 } ,
indexInfo : { remoteIdentityKey : theirIdentityPubKey , closed : - 1 } ,
oldRatchetList : [ ]
} ;
if ( ! isInitiator )
session . indexInfo . baseKey = theirEphemeralPubKey ;
else
session . indexInfo . baseKey = ourEphemeralKey . pubKey ;
// If we're initiating we go ahead and set our first sending ephemeral key now,
// otherwise we figure it out when we first maybeStepRatchet with the remote's ephemeral key
if ( isInitiator ) {
return textsecure . crypto . createKeyPair ( ) . then ( function ( ourSendingEphemeralKey ) {
session . currentRatchet . ephemeralKeyPair = ourSendingEphemeralKey ;
return calculateRatchet ( session , theirSignedPubKey , true ) . then ( function ( ) {
return session ;
} ) ;
} ) ;
} else {
session . currentRatchet . ephemeralKeyPair = ourSignedKey ;
return session ;
}
} ) ;
} ) ;
}
var promise ;
if ( ourEphemeralKey === undefined || theirEphemeralPubKey === undefined )
promise = Promise . resolve ( new ArrayBuffer ( 0 ) ) ;
else
promise = textsecure . crypto . ECDHE ( theirEphemeralPubKey , ourEphemeralKey . privKey ) ;
return promise . then ( function ( ecRes4 ) {
sharedSecret . set ( new Uint8Array ( ecRes4 ) , 32 * 4 ) ;
if ( isInitiator )
return textsecure . crypto . ECDHE ( theirIdentityPubKey , ourSignedKey . privKey ) . then ( function ( ecRes2 ) {
sharedSecret . set ( new Uint8Array ( ecRes1 ) , 32 ) ;
sharedSecret . set ( new Uint8Array ( ecRes2 ) , 32 * 2 ) ;
} ) . then ( finishInit ) ;
else
return textsecure . crypto . ECDHE ( theirIdentityPubKey , ourSignedKey . privKey ) . then ( function ( ecRes2 ) {
sharedSecret . set ( new Uint8Array ( ecRes1 ) , 32 * 2 ) ;
sharedSecret . set ( new Uint8Array ( ecRes2 ) , 32 )
} ) . then ( finishInit ) ;
} ) ;
} ) ;
}
var removeOldChains = function ( session ) {
// Sending ratchets are always removed when we step because we never need them again
// Receiving ratchets are either removed if we step with all keys used up to previousCounter
// and are otherwise added to the oldRatchetList, which we parse here and remove ratchets
// older than a week (we assume the message was lost and move on with our lives at that point)
var newList = [ ] ;
for ( var i = 0 ; i < session . oldRatchetList . length ; i ++ ) {
var entry = session . oldRatchetList [ i ] ;
var ratchet = getString ( entry . ephemeralKey ) ;
console . log ( "Checking old chain with added time " + ( entry . added / 1000 ) ) ;
if ( ( ! objectContainsKeys ( session [ ratchet ] . messageKeys ) && ( session [ ratchet ] . chainKey === undefined || session [ ratchet ] . chainKey . key === undefined ) )
|| entry . added < new Date ( ) . getTime ( ) - MESSAGE _LOST _THRESHOLD _MS ) {
delete session [ ratchet ] ;
console . log ( "...deleted" ) ;
} else
newList [ newList . length ] = entry ;
}
session . oldRatchetList = newList ;
}
var closeSession = function ( session , sessionClosedByRemote ) {
if ( session . indexInfo . closed > - 1 )
return ;
// After this has run, we can still receive messages on ratchet chains which
// were already open (unless we know we dont need them),
// but we cannot send messages or step the ratchet
// Delete current sending ratchet
delete session [ getString ( session . currentRatchet . ephemeralKeyPair . pubKey ) ] ;
// Move all receive ratchets to the oldRatchetList to mark them for deletion
for ( var i in session ) {
if ( session [ i ] . chainKey !== undefined && session [ i ] . chainKey . key !== undefined ) {
if ( ! sessionClosedByRemote )
session . oldRatchetList [ session . oldRatchetList . length ] = { added : new Date ( ) . getTime ( ) , ephemeralKey : i } ;
else
delete session [ i ] . chainKey . key ;
}
}
// Delete current root key and our ephemeral key pair to disallow ratchet stepping
delete session . currentRatchet [ 'rootKey' ] ;
delete session . currentRatchet [ 'ephemeralKeyPair' ] ;
session . indexInfo . closed = new Date ( ) . getTime ( ) ;
removeOldChains ( session ) ;
}
self . closeOpenSessionForDevice = function ( encodedNumber ) {
var session = crypto _storage . getOpenSession ( encodedNumber ) ;
if ( session === undefined )
return ;
closeSession ( session ) ;
crypto _storage . saveSession ( encodedNumber , session ) ;
}
var initSessionFromPreKeyWhisperMessage ;
var decryptWhisperMessage ;
var handlePreKeyWhisperMessage = function ( from , encodedMessage ) {
var preKeyProto = textsecure . protobuf . PreKeyWhisperMessage . decode ( encodedMessage , 'binary' ) ;
return initSessionFromPreKeyWhisperMessage ( from , preKeyProto ) . then ( function ( sessions ) {
return decryptWhisperMessage ( from , getString ( preKeyProto . message ) , sessions [ 0 ] , preKeyProto . registrationId ) . then ( function ( result ) {
if ( sessions [ 1 ] !== undefined )
sessions [ 1 ] ( ) ;
return result ;
} ) ;
} ) ;
}
var wipeIdentityAndTryMessageAgain = function ( from , encodedMessage , message _id ) {
// Wipe identity key!
textsecure . storage . removeEncrypted ( "devices" + from . split ( '.' ) [ 0 ] ) ;
return handlePreKeyWhisperMessage ( from , encodedMessage ) . then (
function ( pushMessageContent ) {
extension . trigger ( 'message:decrypted' , {
message _id : message _id ,
data : pushMessageContent
} ) ;
}
) ;
}
textsecure . replay . registerFunction ( wipeIdentityAndTryMessageAgain , textsecure . replay . Type . INIT _SESSION ) ;
initSessionFromPreKeyWhisperMessage = function ( encodedNumber , message ) {
var preKeyPair = crypto _storage . getStoredKeyPair ( "preKey" + message . preKeyId ) ;
var signedPreKeyPair = crypto _storage . getStoredKeyPair ( "signedKey" + message . signedPreKeyId ) ;
var session = crypto _storage . getSessionOrIdentityKeyByBaseKey ( encodedNumber , toArrayBuffer ( message . baseKey ) ) ;
var open _session = crypto _storage . getOpenSession ( encodedNumber ) ;
if ( signedPreKeyPair === undefined ) {
// Session may or may not be the right one, but if its not, we can't do anything about it
// ...fall through and let decryptWhisperMessage handle that case
if ( session !== undefined && session . currentRatchet !== undefined )
return Promise . resolve ( [ session , undefined ] ) ;
else
throw new Error ( "Missing Signed PreKey for PreKeyWhisperMessage" ) ;
}
if ( session !== undefined ) {
// Duplicate PreKeyMessage for session:
if ( isEqual ( session . indexInfo . baseKey , message . baseKey , false ) )
return Promise . resolve ( [ session , undefined ] ) ;
// We already had a session/known identity key:
if ( isEqual ( session . indexInfo . remoteIdentityKey , message . identityKey , false ) ) {
// If the identity key matches the previous one, close the previous one and use the new one
if ( open _session !== undefined )
closeSession ( open _session ) ; // To be returned and saved later
} else {
// ...otherwise create an error that the UI will pick up and ask the user if they want to re-negotiate
throw new textsecure . IncomingIdentityKeyError ( encodedNumber , getString ( message . encode ( ) ) ) ;
}
}
return initSession ( false , preKeyPair , signedPreKeyPair , encodedNumber , toArrayBuffer ( message . identityKey ) , toArrayBuffer ( message . baseKey ) , undefined )
. then ( function ( new _session ) {
// Note that the session is not actually saved until the very end of decryptWhisperMessage
// ... to ensure that the sender actually holds the private keys for all reported pubkeys
return [ new _session , function ( ) {
if ( open _session !== undefined )
crypto _storage . saveSession ( encodedNumber , open _session ) ;
crypto _storage . removeStoredKeyPair ( "preKey" + message . preKeyId ) ;
} ] ;
} ) ; ;
}
var fillMessageKeys = function ( chain , counter ) {
if ( chain . chainKey . counter + 1000 < counter ) //TODO: maybe 1000 is too low/high in some cases?
return Promise . resolve ( ) ; // Stalker, much?
if ( chain . chainKey . counter >= counter )
return Promise . resolve ( ) ; // Already calculated
if ( chain . chainKey . key === undefined )
throw new Error ( "Got invalid request to extend chain after it was already closed" ) ;
var key = toArrayBuffer ( chain . chainKey . key ) ;
var byteArray = new Uint8Array ( 1 ) ;
byteArray [ 0 ] = 1 ;
return textsecure . crypto . sign ( key , byteArray . buffer ) . then ( function ( mac ) {
byteArray [ 0 ] = 2 ;
return textsecure . crypto . sign ( key , byteArray . buffer ) . then ( function ( key ) {
chain . messageKeys [ chain . chainKey . counter + 1 ] = mac ;
chain . chainKey . key = key
chain . chainKey . counter += 1 ;
return fillMessageKeys ( chain , counter ) ;
} ) ;
} ) ;
}
var maybeStepRatchet = function ( session , remoteKey , previousCounter ) {
if ( session [ getString ( remoteKey ) ] !== undefined )
return Promise . resolve ( ) ;
var ratchet = session . currentRatchet ;
var finish = function ( ) {
return calculateRatchet ( session , remoteKey , false ) . then ( function ( ) {
// Now swap the ephemeral key and calculate the new sending chain
var previousRatchet = getString ( ratchet . ephemeralKeyPair . pubKey ) ;
if ( session [ previousRatchet ] !== undefined ) {
ratchet . previousCounter = session [ previousRatchet ] . chainKey . counter ;
delete session [ previousRatchet ] ;
}
return textsecure . crypto . createKeyPair ( ) . then ( function ( keyPair ) {
ratchet . ephemeralKeyPair = keyPair ;
return calculateRatchet ( session , remoteKey , true ) . then ( function ( ) {
ratchet . lastRemoteEphemeralKey = remoteKey ;
} ) ;
} ) ;
} ) ;
}
var previousRatchet = session [ getString ( ratchet . lastRemoteEphemeralKey ) ] ;
if ( previousRatchet !== undefined ) {
return fillMessageKeys ( previousRatchet , previousCounter ) . then ( function ( ) {
delete previousRatchet . chainKey . key ;
if ( ! objectContainsKeys ( previousRatchet . messageKeys ) )
delete session [ getString ( ratchet . lastRemoteEphemeralKey ) ] ;
else
session . oldRatchetList [ session . oldRatchetList . length ] = { added : new Date ( ) . getTime ( ) , ephemeralKey : ratchet . lastRemoteEphemeralKey } ;
} ) . then ( finish ) ;
} else
return finish ( ) ;
}
// returns decrypted protobuf
decryptWhisperMessage = function ( encodedNumber , messageBytes , session , registrationId ) {
if ( messageBytes [ 0 ] != String . fromCharCode ( ( 3 << 4 ) | 3 ) )
throw new Error ( "Bad version number on WhisperMessage" ) ;
var messageProto = messageBytes . substring ( 1 , messageBytes . length - 8 ) ;
var mac = messageBytes . substring ( messageBytes . length - 8 , messageBytes . length ) ;
var message = textsecure . protobuf . WhisperMessage . decode ( messageProto , 'binary' ) ;
var remoteEphemeralKey = toArrayBuffer ( message . ephemeralKey ) ;
if ( session === undefined ) {
var session = crypto _storage . getSessionByRemoteEphemeralKey ( encodedNumber , remoteEphemeralKey ) ;
if ( session === undefined )
throw new Error ( "No session found to decrypt message from " + encodedNumber ) ;
}
return maybeStepRatchet ( session , remoteEphemeralKey , message . previousCounter ) . then ( function ( ) {
var chain = session [ getString ( message . ephemeralKey ) ] ;
return fillMessageKeys ( chain , message . counter ) . then ( function ( ) {
return HKDF ( toArrayBuffer ( chain . messageKeys [ message . counter ] ) , '' , "WhisperMessageKeys" ) . then ( function ( keys ) {
delete chain . messageKeys [ message . counter ] ;
var messageProtoArray = toArrayBuffer ( messageProto ) ;
var macInput = new Uint8Array ( messageProtoArray . byteLength + 33 * 2 + 1 ) ;
macInput . set ( new Uint8Array ( toArrayBuffer ( session . indexInfo . remoteIdentityKey ) ) ) ;
macInput . set ( new Uint8Array ( toArrayBuffer ( crypto _storage . getIdentityKey ( ) . pubKey ) ) , 33 ) ;
macInput [ 33 * 2 ] = ( 3 << 4 ) | 3 ;
macInput . set ( new Uint8Array ( messageProtoArray ) , 33 * 2 + 1 ) ;
return verifyMAC ( macInput . buffer , keys [ 1 ] , mac ) . then ( function ( ) {
return window . textsecure . crypto . decrypt ( keys [ 0 ] , toArrayBuffer ( message . ciphertext ) , keys [ 2 ] . slice ( 0 , 16 ) )
. then ( function ( paddedPlaintext ) {
paddedPlaintext = new Uint8Array ( paddedPlaintext ) ;
var plaintext ;
for ( var i = paddedPlaintext . length - 1 ; i >= 0 ; i -- ) {
if ( paddedPlaintext [ i ] == 0x80 ) {
plaintext = new Uint8Array ( i ) ;
plaintext . set ( paddedPlaintext . subarray ( 0 , i ) ) ;
plaintext = plaintext . buffer ;
break ;
} else if ( paddedPlaintext [ i ] != 0x00 )
throw new Error ( 'Invalid padding' ) ;
}
delete session [ 'pendingPreKey' ] ;
var finalMessage = textsecure . protobuf . PushMessageContent . decode ( plaintext ) ;
if ( ( finalMessage . flags & textsecure . protobuf . PushMessageContent . Flags . END _SESSION )
== textsecure . protobuf . PushMessageContent . Flags . END _SESSION )
closeSession ( session , true ) ;
removeOldChains ( session ) ;
crypto _storage . saveSession ( encodedNumber , session , registrationId ) ;
return finalMessage ;
} ) ;
} ) ;
} ) ;
} ) ;
} ) ;
}
/ * * * * * * * * * * * * * * * * * * * * * * * * *
* * * Public crypto API * * *
* * * * * * * * * * * * * * * * * * * * * * * * * /
// Decrypts message into a raw string
self . decryptWebsocketMessage = function ( message ) {
var signaling _key = textsecure . storage . getEncrypted ( "signaling_key" ) ; //TODO: in crypto_storage
var aes _key = toArrayBuffer ( signaling _key . substring ( 0 , 32 ) ) ;
var mac _key = toArrayBuffer ( signaling _key . substring ( 32 , 32 + 20 ) ) ;
var decodedMessage = message . toArrayBuffer ( ) ;
if ( new Uint8Array ( decodedMessage ) [ 0 ] != 1 )
throw new Error ( "Got bad version number: " + decodedMessage [ 0 ] ) ;
var iv = decodedMessage . slice ( 1 , 1 + 16 ) ;
var ciphertext = decodedMessage . slice ( 1 + 16 , decodedMessage . byteLength - 10 ) ;
var ivAndCiphertext = decodedMessage . slice ( 0 , decodedMessage . byteLength - 10 ) ;
var mac = decodedMessage . slice ( decodedMessage . byteLength - 10 , decodedMessage . byteLength ) ;
return verifyMAC ( ivAndCiphertext , mac _key , mac ) . then ( function ( ) {
return window . textsecure . crypto . decrypt ( aes _key , ciphertext , iv ) ;
} ) ;
} ;
self . decryptAttachment = function ( encryptedBin , keys ) {
var aes _key = keys . slice ( 0 , 32 ) ;
var mac _key = keys . slice ( 32 , 64 ) ;
var iv = encryptedBin . slice ( 0 , 16 ) ;
var ciphertext = encryptedBin . slice ( 16 , encryptedBin . byteLength - 32 ) ;
var ivAndCiphertext = encryptedBin . slice ( 0 , encryptedBin . byteLength - 32 ) ;
var mac = encryptedBin . slice ( encryptedBin . byteLength - 32 , encryptedBin . byteLength ) ;
return verifyMAC ( ivAndCiphertext , mac _key , mac ) . then ( function ( ) {
return window . textsecure . crypto . decrypt ( aes _key , ciphertext , iv ) ;
} ) ;
} ;
self . encryptAttachment = function ( plaintext , keys , iv ) {
var aes _key = keys . slice ( 0 , 32 ) ;
var mac _key = keys . slice ( 32 , 64 ) ;
return window . textsecure . crypto . encrypt ( aes _key , plaintext , iv ) . then ( function ( ciphertext ) {
var ivAndCiphertext = new Uint8Array ( 16 + ciphertext . byteLength ) ;
ivAndCiphertext . set ( new Uint8Array ( iv ) ) ;
ivAndCiphertext . set ( new Uint8Array ( ciphertext ) , 16 ) ;
return textsecure . crypto . sign ( mac _key , ivAndCiphertext . buffer ) . then ( function ( mac ) {
var encryptedBin = new Uint8Array ( 16 + ciphertext . byteLength + 32 ) ;
encryptedBin . set ( ivAndCiphertext ) ;
encryptedBin . set ( new Uint8Array ( mac ) , 16 + ciphertext . byteLength ) ;
return encryptedBin . buffer ;
} ) ;
} ) ;
} ;
self . handleIncomingPushMessageProto = function ( proto ) {
switch ( proto . type ) {
case textsecure . protobuf . IncomingPushMessageSignal . Type . PLAINTEXT :
return Promise . resolve ( textsecure . protobuf . PushMessageContent . decode ( proto . message ) ) ;
case textsecure . protobuf . IncomingPushMessageSignal . Type . CIPHERTEXT :
var from = proto . source + "." + ( proto . sourceDevice == null ? 0 : proto . sourceDevice ) ;
return decryptWhisperMessage ( from , getString ( proto . message ) ) ;
case textsecure . protobuf . IncomingPushMessageSignal . Type . PREKEY _BUNDLE :
if ( proto . message . readUint8 ( ) != ( ( 3 << 4 ) | 3 ) )
throw new Error ( "Bad version byte" ) ;
var from = proto . source + "." + ( proto . sourceDevice == null ? 0 : proto . sourceDevice ) ;
return handlePreKeyWhisperMessage ( from , getString ( proto . message ) ) ;
case textsecure . protobuf . IncomingPushMessageSignal . Type . RECEIPT :
return Promise . resolve ( null ) ;
default :
return new Promise ( function ( resolve , reject ) { reject ( new Error ( "Unknown message type" ) ) ; } ) ;
}
}
// return Promise(encoded [PreKey]WhisperMessage)
self . encryptMessageFor = function ( deviceObject , pushMessageContent ) {
var session = crypto _storage . getOpenSession ( deviceObject . encodedNumber ) ;
var doEncryptPushMessageContent = function ( ) {
var msg = new textsecure . protobuf . WhisperMessage ( ) ;
var plaintext = toArrayBuffer ( pushMessageContent . encode ( ) ) ;
var paddedPlaintext = new Uint8Array ( Math . ceil ( ( plaintext . byteLength + 1 ) / 160.0 ) * 160 - 1 ) ;
paddedPlaintext . set ( new Uint8Array ( plaintext ) ) ;
paddedPlaintext [ plaintext . byteLength ] = 0x80 ;
msg . ephemeralKey = toArrayBuffer ( session . currentRatchet . ephemeralKeyPair . pubKey ) ;
var chain = session [ getString ( msg . ephemeralKey ) ] ;
return fillMessageKeys ( chain , chain . chainKey . counter + 1 ) . then ( function ( ) {
return HKDF ( toArrayBuffer ( chain . messageKeys [ chain . chainKey . counter ] ) , '' , "WhisperMessageKeys" ) . then ( function ( keys ) {
delete chain . messageKeys [ chain . chainKey . counter ] ;
msg . counter = chain . chainKey . counter ;
msg . previousCounter = session . currentRatchet . previousCounter ;
return window . textsecure . crypto . encrypt ( keys [ 0 ] , paddedPlaintext . buffer , keys [ 2 ] . slice ( 0 , 16 ) ) . then ( function ( ciphertext ) {
msg . ciphertext = ciphertext ;
var encodedMsg = toArrayBuffer ( msg . encode ( ) ) ;
var macInput = new Uint8Array ( encodedMsg . byteLength + 33 * 2 + 1 ) ;
macInput . set ( new Uint8Array ( toArrayBuffer ( crypto _storage . getIdentityKey ( ) . pubKey ) ) ) ;
macInput . set ( new Uint8Array ( toArrayBuffer ( session . indexInfo . remoteIdentityKey ) ) , 33 ) ;
macInput [ 33 * 2 ] = ( 3 << 4 ) | 3 ;
macInput . set ( new Uint8Array ( encodedMsg ) , 33 * 2 + 1 ) ;
return textsecure . crypto . sign ( keys [ 1 ] , macInput . buffer ) . then ( function ( mac ) {
var result = new Uint8Array ( encodedMsg . byteLength + 9 ) ;
result [ 0 ] = ( 3 << 4 ) | 3 ;
result . set ( new Uint8Array ( encodedMsg ) , 1 ) ;
result . set ( new Uint8Array ( mac , 0 , 8 ) , encodedMsg . byteLength + 1 ) ;
try {
delete deviceObject [ 'signedKey' ] ;
delete deviceObject [ 'signedKeyId' ] ;
delete deviceObject [ 'preKey' ] ;
delete deviceObject [ 'preKeyId' ] ;
} catch ( _ ) { }
removeOldChains ( session ) ;
crypto _storage . saveSessionAndDevice ( deviceObject , session ) ;
return result ;
} ) ;
} ) ;
} ) ;
} ) ;
}
var preKeyMsg = new textsecure . protobuf . PreKeyWhisperMessage ( ) ;
preKeyMsg . identityKey = toArrayBuffer ( crypto _storage . getIdentityKey ( ) . pubKey ) ;
preKeyMsg . registrationId = textsecure . storage . getUnencrypted ( "registrationId" ) ;
if ( session === undefined ) {
return textsecure . crypto . createKeyPair ( ) . then ( function ( baseKey ) {
preKeyMsg . preKeyId = deviceObject . preKeyId ;
preKeyMsg . signedPreKeyId = deviceObject . signedKeyId ;
preKeyMsg . baseKey = toArrayBuffer ( baseKey . pubKey ) ;
return initSession ( true , baseKey , undefined , deviceObject . encodedNumber ,
toArrayBuffer ( deviceObject . identityKey ) , toArrayBuffer ( deviceObject . preKey ) , toArrayBuffer ( deviceObject . signedKey ) )
. then ( function ( new _session ) {
session = new _session ;
session . pendingPreKey = { preKeyId : deviceObject . preKeyId , signedKeyId : deviceObject . signedKeyId , baseKey : baseKey . pubKey } ;
return doEncryptPushMessageContent ( ) . then ( function ( message ) {
preKeyMsg . message = message ;
var result = String . fromCharCode ( ( 3 << 4 ) | 3 ) + getString ( preKeyMsg . encode ( ) ) ;
return { type : 3 , body : result } ;
} ) ;
} ) ;
} ) ;
} else
return doEncryptPushMessageContent ( ) . then ( function ( message ) {
if ( session . pendingPreKey !== undefined ) {
preKeyMsg . baseKey = toArrayBuffer ( session . pendingPreKey . baseKey ) ;
preKeyMsg . preKeyId = session . pendingPreKey . preKeyId ;
preKeyMsg . signedPreKeyId = session . pendingPreKey . signedKeyId ;
preKeyMsg . message = message ;
var result = String . fromCharCode ( ( 3 << 4 ) | 3 ) + getString ( preKeyMsg . encode ( ) ) ;
return { type : 3 , body : result } ;
} else
return { type : 1 , body : getString ( message ) } ;
} ) ;
}
var GENERATE _KEYS _KEYS _GENERATED = 100 ;
self . generateKeys = function ( ) {
var identityKeyPair = crypto _storage . getIdentityKey ( ) ;
var identityKeyCalculated = function ( identityKeyPair ) {
var firstPreKeyId = textsecure . storage . getEncrypted ( "maxPreKeyId" , 0 ) ;
textsecure . storage . putEncrypted ( "maxPreKeyId" , firstPreKeyId + GENERATE _KEYS _KEYS _GENERATED ) ;
var signedKeyId = textsecure . storage . getEncrypted ( "signedKeyId" , 0 ) ;
textsecure . storage . putEncrypted ( "signedKeyId" , signedKeyId + 1 ) ;
var keys = { } ;
keys . identityKey = identityKeyPair . pubKey ;
keys . preKeys = [ ] ;
var generateKey = function ( keyId ) {
return crypto _storage . getNewStoredKeyPair ( "preKey" + keyId , false ) . then ( function ( keyPair ) {
keys . preKeys [ keyId ] = { keyId : keyId , publicKey : keyPair . pubKey } ;
} ) ;
} ;
var promises = [ ] ;
for ( var i = firstPreKeyId ; i < firstPreKeyId + GENERATE _KEYS _KEYS _GENERATED ; i ++ )
promises [ i ] = generateKey ( i ) ;
promises [ firstPreKeyId + GENERATE _KEYS _KEYS _GENERATED ] = crypto _storage . getNewStoredKeyPair ( "signedKey" + signedKeyId ) . then ( function ( keyPair ) {
return textsecure . crypto . Ed25519Sign ( identityKeyPair . privKey , keyPair . pubKey ) . then ( function ( sig ) {
keys . signedPreKey = { keyId : signedKeyId , publicKey : keyPair . pubKey , signature : sig } ;
} ) ;
} ) ;
//TODO: Process by date added and agressively call generateKeys when we get near maxPreKeyId in a message
crypto _storage . removeStoredKeyPair ( "signedKey" + ( signedKeyId - 2 ) ) ;
return Promise . all ( promises ) . then ( function ( ) {
return keys ;
} ) ;
}
if ( identityKeyPair === undefined )
return crypto _storage . getNewStoredKeyPair ( "identityKey" ) . then ( function ( keyPair ) { return identityKeyCalculated ( keyPair ) ; } ) ;
else
return identityKeyCalculated ( identityKeyPair ) ;
}
//TODO: Dont always update prekeys here
if ( textsecure . storage . getEncrypted ( "lastSignedKeyUpdate" , Date . now ( ) ) < Date . now ( ) - MESSAGE _LOST _THRESHOLD _MS ) {
new Promise ( function ( resolve ) { resolve ( self . generateKeys ( ) ) ; } ) ;
}
self . prepareTempWebsocket = function ( ) {
var socketInfo = { } ;
var keyPair ;
socketInfo . decryptAndHandleDeviceInit = function ( deviceInit ) {
2015-01-23 11:19:29 -10:00
var masterEphemeral = toArrayBuffer ( deviceInit . publicKey ) ;
var message = toArrayBuffer ( deviceInit . body ) ;
2015-01-13 14:09:32 -10:00
return textsecure . crypto . ECDHE ( masterEphemeral , keyPair . privKey ) . then ( function ( ecRes ) {
2015-01-23 11:19:29 -10:00
return HKDF ( ecRes , '' , "TextSecure Provisioning Message" ) . then ( function ( keys ) {
if ( new Uint8Array ( message ) [ 0 ] != 1 )
throw new Error ( "Bad version number on ProvisioningMessage" ) ;
2015-01-13 14:09:32 -10:00
var iv = message . slice ( 1 , 16 + 1 ) ;
2015-01-23 11:19:29 -10:00
var mac = message . slice ( message . byteLength - 32 , message . byteLength ) ;
var ivAndCiphertext = message . slice ( 0 , message . byteLength - 32 ) ;
var ciphertext = message . slice ( 16 + 1 , message . byteLength - 32 ) ;
2015-01-13 14:09:32 -10:00
2015-01-23 11:19:29 -10:00
return verifyMAC ( ivAndCiphertext , keys [ 1 ] , mac ) . then ( function ( ) {
return window . textsecure . crypto . decrypt ( keys [ 0 ] , ciphertext , iv ) . then ( function ( plaintext ) {
var identityKeyMsg = textsecure . protobuf . ProvisionMessage . decode ( plaintext ) ;
2015-01-13 14:09:32 -10:00
2015-01-23 11:19:29 -10:00
return textsecure . crypto . createKeyPair ( toArrayBuffer ( identityKeyMsg . identityKeyPrivate ) ) . then ( function ( identityKeyPair ) {
2015-01-13 14:09:32 -10:00
crypto _storage . putKeyPair ( "identityKey" , identityKeyPair ) ;
2015-01-23 11:19:29 -10:00
identityKeyMsg . identityKeyPrivate = null ;
2015-01-13 14:09:32 -10:00
return identityKeyMsg ;
} ) ;
} ) ;
} ) ;
} ) ;
} ) ;
}
return textsecure . crypto . createKeyPair ( ) . then ( function ( newKeyPair ) {
keyPair = newKeyPair ;
socketInfo . pubKey = keyPair . pubKey ;
return socketInfo ;
} ) ;
}
return self ;
} ( ) ;
} ) ( ) ;
/ * v i m : t s = 4 : s w = 4 : e x p a n d t a b
*
* This program is free software : you can redistribute it and / or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation , either version 3 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU Lesser General Public License for more details .
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program . If not , see < http : //www.gnu.org/licenses/>.
* /
// sendMessage(numbers = [], message = PushMessageContentProto, callback(success/failure map))
window . textsecure . messaging = function ( ) {
'use strict' ;
var self = { } ;
function getKeysForNumber ( number , updateDevices ) {
var handleResult = function ( response ) {
for ( var i in response . devices ) {
if ( updateDevices === undefined || updateDevices . indexOf ( response . devices [ i ] . deviceId ) > - 1 )
textsecure . storage . devices . saveKeysToDeviceObject ( {
encodedNumber : number + "." + response . devices [ i ] . deviceId ,
identityKey : response . identityKey ,
preKey : response . devices [ i ] . preKey . publicKey ,
preKeyId : response . devices [ i ] . preKey . keyId ,
signedKey : response . devices [ i ] . signedPreKey . publicKey ,
signedKeyId : response . devices [ i ] . signedPreKey . keyId ,
registrationId : response . devices [ i ] . registrationId
} ) ;
}
} ;
var promises = [ ] ;
if ( updateDevices !== undefined )
for ( var i in updateDevices )
promises [ promises . length ] = textsecure . api . getKeysForNumber ( number , updateDevices [ i ] ) . then ( handleResult ) ;
else
return textsecure . api . getKeysForNumber ( number ) . then ( handleResult ) ;
return Promise . all ( promises ) ;
}
// success_callback(server success/failure map), error_callback(error_msg)
// message == PushMessageContentProto (NOT STRING)
function sendMessageToDevices ( timestamp , number , deviceObjectList , message , success _callback , error _callback ) {
var jsonData = [ ] ;
var relay = undefined ;
var promises = [ ] ;
var addEncryptionFor = function ( i ) {
if ( deviceObjectList [ i ] . relay !== undefined ) {
if ( relay === undefined )
relay = deviceObjectList [ i ] . relay ;
else if ( relay != deviceObjectList [ i ] . relay )
return new Promise ( function ( ) { throw new Error ( "Mismatched relays for number " + number ) ; } ) ;
} else {
if ( relay === undefined )
relay = "" ;
else if ( relay != "" )
return new Promise ( function ( ) { throw new Error ( "Mismatched relays for number " + number ) ; } ) ;
}
return textsecure . protocol . encryptMessageFor ( deviceObjectList [ i ] , message ) . then ( function ( encryptedMsg ) {
jsonData [ i ] = {
type : encryptedMsg . type ,
destinationDeviceId : textsecure . utils . unencodeNumber ( deviceObjectList [ i ] . encodedNumber ) [ 1 ] ,
destinationRegistrationId : deviceObjectList [ i ] . registrationId ,
body : encryptedMsg . body ,
timestamp : timestamp
} ;
if ( deviceObjectList [ i ] . relay !== undefined )
jsonData [ i ] . relay = deviceObjectList [ i ] . relay ;
} ) ;
}
for ( var i = 0 ; i < deviceObjectList . length ; i ++ )
promises [ i ] = addEncryptionFor ( i ) ;
return Promise . all ( promises ) . then ( function ( ) {
return textsecure . api . sendMessages ( number , jsonData ) ;
} ) ;
}
var makeAttachmentPointer ;
2015-01-14 11:24:45 -10:00
var refreshGroup = function ( number , groupId , devicesForNumber ) {
groupId = getString ( groupId ) ;
2015-01-13 14:09:32 -10:00
2015-01-14 11:24:45 -10:00
var doUpdate = false ;
for ( var i in devicesForNumber ) {
if ( textsecure . storage . groups . needUpdateByDeviceRegistrationId ( groupId , number , devicesForNumber [ i ] . encodedNumber , devicesForNumber [ i ] . registrationId ) )
doUpdate = true ;
}
if ( ! doUpdate )
return Promise . resolve ( true ) ;
var group = textsecure . storage . groups . getGroup ( groupId ) ;
var numberIndex = group . numbers . indexOf ( number ) ;
if ( numberIndex < 0 ) // This is potentially a multi-message rare racing-AJAX race
return Promise . reject ( "Tried to refresh group to non-member" ) ;
var proto = new textsecure . protobuf . PushMessageContent ( ) ;
proto . group = new textsecure . protobuf . PushMessageContent . GroupContext ( ) ;
proto . group . id = toArrayBuffer ( group . id ) ;
proto . group . type = textsecure . protobuf . PushMessageContent . GroupContext . Type . UPDATE ;
proto . group . members = group . numbers ;
proto . group . name = group . name === undefined ? null : group . name ;
if ( group . avatar !== undefined ) {
return makeAttachmentPointer ( group . avatar ) . then ( function ( attachment ) {
proto . group . avatar = attachment ;
return sendMessageToDevices ( Date . now ( ) , number , devicesForNumber , proto ) ;
} ) ;
} else {
return sendMessageToDevices ( Date . now ( ) , number , devicesForNumber , proto ) ;
2015-01-13 14:09:32 -10:00
}
}
var tryMessageAgain = function ( number , encodedMessage , message _id ) {
var message = new Whisper . MessageCollection ( ) . add ( { id : message _id } ) ;
message . fetch ( ) . then ( function ( ) {
textsecure . storage . removeEncrypted ( "devices" + number ) ;
var proto = textsecure . protobuf . PushMessageContent . decode ( encodedMessage , 'binary' ) ;
sendMessageProto ( message . get ( 'sent_at' ) , [ number ] , proto , function ( res ) {
2015-01-14 11:24:45 -10:00
if ( res . failure . length > 0 )
2015-01-13 14:09:32 -10:00
message . set ( 'errors' , res . failure ) ;
2015-01-14 11:24:45 -10:00
else
2015-01-13 14:09:32 -10:00
message . set ( 'errors' , [ ] ) ;
message . save ( ) . then ( function ( ) {
extension . trigger ( 'message' , message ) ; // notify frontend listeners
} ) ;
} ) ;
} ) ;
} ;
textsecure . replay . registerFunction ( tryMessageAgain , textsecure . replay . Type . SEND _MESSAGE ) ;
var sendMessageProto = function ( timestamp , numbers , message , callback ) {
var numbersCompleted = 0 ;
var errors = [ ] ;
var successfulNumbers = [ ] ;
var numberCompleted = function ( ) {
numbersCompleted ++ ;
if ( numbersCompleted >= numbers . length )
callback ( { success : successfulNumbers , failure : errors } ) ;
}
var registerError = function ( number , message , error ) {
if ( error ) {
if ( error . humanError )
message = error . humanError ;
} else
error = new Error ( message ) ;
errors [ errors . length ] = { number : number , reason : message , error : error } ;
numberCompleted ( ) ;
}
var doSendMessage ;
var reloadDevicesAndSend = function ( number , recurse ) {
return function ( ) {
var devicesForNumber = textsecure . storage . devices . getDeviceObjectsForNumber ( number ) ;
if ( devicesForNumber . length == 0 )
return registerError ( number , "Got empty device list when loading device keys" , null ) ;
2015-01-14 11:24:45 -10:00
doSendMessage ( number , devicesForNumber , recurse ) ;
2015-01-13 14:09:32 -10:00
}
}
doSendMessage = function ( number , devicesForNumber , recurse ) {
2015-01-14 11:24:45 -10:00
var groupUpdate = Promise . resolve ( true ) ;
if ( message . group && message . group . id )
groupUpdate = refreshGroup ( number , message . group . id , devicesForNumber ) ;
return groupUpdate . then ( function ( ) {
return sendMessageToDevices ( timestamp , number , devicesForNumber , message ) . then ( function ( result ) {
successfulNumbers [ successfulNumbers . length ] = number ;
numberCompleted ( ) ;
} ) ;
2015-01-13 14:09:32 -10:00
} ) . catch ( function ( error ) {
if ( error instanceof Error && error . name == "HTTPError" && ( error . message == 410 || error . message == 409 ) ) {
if ( ! recurse )
return registerError ( number , "Hit retry limit attempting to reload device list" , error ) ;
if ( error . message == 409 )
textsecure . storage . devices . removeDeviceIdsForNumber ( number , error . response . extraDevices ) ;
var resetDevices = ( ( error . message == 410 ) ? error . response . staleDevices : error . response . missingDevices ) ;
getKeysForNumber ( number , resetDevices )
. then ( reloadDevicesAndSend ( number , false ) )
. catch ( function ( error ) {
if ( error . message !== "Identity key changed" )
registerError ( number , "Failed to reload device keys" , error ) ;
else {
error = new textsecure . OutgoingIdentityKeyError ( number , getString ( message . encode ( ) ) ) ;
registerError ( number , "Identity key changed" , error ) ;
}
} ) ;
} else
registerError ( number , "Failed to create or send message" , error ) ;
} ) ;
}
2015-01-15 19:58:18 -10:00
var getDevicesAndSendToNumber = function ( number ) {
2015-01-13 14:09:32 -10:00
var devicesForNumber = textsecure . storage . devices . getDeviceObjectsForNumber ( number ) ;
var promises = [ ] ;
for ( var j in devicesForNumber )
if ( devicesForNumber [ j ] . registrationId === undefined )
promises [ promises . length ] = getKeysForNumber ( number , [ parseInt ( textsecure . utils . unencodeNumber ( devicesForNumber [ j ] . encodedNumber ) [ 1 ] ) ] ) ;
Promise . all ( promises ) . then ( function ( ) {
devicesForNumber = textsecure . storage . devices . getDeviceObjectsForNumber ( number ) ;
if ( devicesForNumber . length == 0 ) {
getKeysForNumber ( number )
. then ( reloadDevicesAndSend ( number , true ) )
. catch ( function ( error ) {
registerError ( number , "Failed to retreive new device keys for number " + number , error ) ;
} ) ;
} else
doSendMessage ( number , devicesForNumber , true ) ;
} ) ;
2015-01-13 15:23:11 -10:00
}
2015-01-15 19:58:18 -10:00
for ( var i in numbers )
getDevicesAndSendToNumber ( numbers [ i ] ) ;
2015-01-13 14:09:32 -10:00
}
makeAttachmentPointer = function ( attachment ) {
var proto = new textsecure . protobuf . PushMessageContent . AttachmentPointer ( ) ;
proto . key = textsecure . crypto . getRandomBytes ( 64 ) ;
var iv = textsecure . crypto . getRandomBytes ( 16 ) ;
return textsecure . protocol . encryptAttachment ( attachment . data , proto . key , iv ) . then ( function ( encryptedBin ) {
return textsecure . api . putAttachment ( encryptedBin ) . then ( function ( id ) {
proto . id = id ;
proto . contentType = attachment . contentType ;
return proto ;
} ) ;
} ) ;
}
var sendIndividualProto = function ( number , proto , timestamp ) {
return new Promise ( function ( resolve , reject ) {
sendMessageProto ( timestamp , [ number ] , proto , function ( res ) {
if ( res . failure . length > 0 )
reject ( res . failure ) ;
else
resolve ( ) ;
} ) ;
} ) ;
}
2015-01-14 11:24:45 -10:00
var sendGroupProto = function ( numbers , proto , timestamp ) {
2015-01-13 14:09:32 -10:00
timestamp = timestamp || Date . now ( ) ;
var me = textsecure . utils . unencodeNumber ( textsecure . storage . getUnencrypted ( "number_id" ) ) [ 0 ] ;
numbers = numbers . filter ( function ( number ) { return number != me ; } ) ;
return new Promise ( function ( resolve , reject ) {
sendMessageProto ( timestamp , numbers , proto , function ( res ) {
if ( res . failure . length > 0 )
reject ( res . failure ) ;
else
resolve ( ) ;
} ) ;
} ) ;
}
self . sendMessageToNumber = function ( number , messageText , attachments , timestamp ) {
var proto = new textsecure . protobuf . PushMessageContent ( ) ;
proto . body = messageText ;
var promises = [ ] ;
for ( var i in attachments )
promises . push ( makeAttachmentPointer ( attachments [ i ] ) ) ;
return Promise . all ( promises ) . then ( function ( attachmentsArray ) {
proto . attachments = attachmentsArray ;
return sendIndividualProto ( number , proto , timestamp ) ;
} ) ;
}
self . closeSession = function ( number ) {
var proto = new textsecure . protobuf . PushMessageContent ( ) ;
proto . body = "TERMINATE" ;
proto . flags = textsecure . protobuf . PushMessageContent . Flags . END _SESSION ;
return sendIndividualProto ( number , proto ) . then ( function ( res ) {
var devices = textsecure . storage . devices . getDeviceObjectsForNumber ( number ) ;
for ( var i in devices )
textsecure . protocol . closeOpenSessionForDevice ( devices [ i ] . encodedNumber ) ;
return res ;
} ) ;
}
self . sendMessageToGroup = function ( groupId , messageText , attachments , timestamp ) {
var proto = new textsecure . protobuf . PushMessageContent ( ) ;
proto . body = messageText ;
proto . group = new textsecure . protobuf . PushMessageContent . GroupContext ( ) ;
proto . group . id = toArrayBuffer ( groupId ) ;
proto . group . type = textsecure . protobuf . PushMessageContent . GroupContext . Type . DELIVER ;
var numbers = textsecure . storage . groups . getNumbers ( groupId ) ;
if ( numbers === undefined )
return new Promise ( function ( resolve , reject ) { reject ( new Error ( "Unknown Group" ) ) ; } ) ;
var promises = [ ] ;
for ( var i in attachments )
promises . push ( makeAttachmentPointer ( attachments [ i ] ) ) ;
return Promise . all ( promises ) . then ( function ( attachmentsArray ) {
proto . attachments = attachmentsArray ;
return sendGroupProto ( numbers , proto , timestamp ) ;
} ) ;
}
self . createGroup = function ( numbers , name , avatar ) {
var proto = new textsecure . protobuf . PushMessageContent ( ) ;
proto . group = new textsecure . protobuf . PushMessageContent . GroupContext ( ) ;
var group = textsecure . storage . groups . createNewGroup ( numbers ) ;
proto . group . id = toArrayBuffer ( group . id ) ;
var numbers = group . numbers ;
proto . group . type = textsecure . protobuf . PushMessageContent . GroupContext . Type . UPDATE ;
proto . group . members = numbers ;
proto . group . name = name ;
if ( avatar !== undefined ) {
return makeAttachmentPointer ( avatar ) . then ( function ( attachment ) {
proto . group . avatar = attachment ;
2015-01-13 13:27:18 -10:00
return sendGroupProto ( numbers , proto ) . then ( function ( ) {
return proto . group . id ;
} ) ;
} ) ;
} else {
return sendGroupProto ( numbers , proto ) . then ( function ( ) {
return proto . group . id ;
} ) ;
}
}
self . updateGroup = function ( groupId , name , avatar , numbers ) {
var proto = new textsecure . protobuf . PushMessageContent ( ) ;
proto . group = new textsecure . protobuf . PushMessageContent . GroupContext ( ) ;
proto . group . id = toArrayBuffer ( groupId ) ;
proto . group . type = textsecure . protobuf . PushMessageContent . GroupContext . Type . UPDATE ;
proto . group . name = name ;
var numbers = textsecure . storage . groups . addNumbers ( groupId , numbers ) ;
if ( numbers === undefined ) {
return new Promise ( function ( resolve , reject ) { reject ( new Error ( "Unknown Group" ) ) ; } ) ;
}
proto . group . members = numbers ;
if ( avatar !== undefined ) {
return makeAttachmentPointer ( avatar ) . then ( function ( attachment ) {
proto . group . avatar = attachment ;
2015-01-13 14:09:32 -10:00
return sendGroupProto ( numbers , proto ) . then ( function ( ) {
return proto . group . id ;
} ) ;
} ) ;
} else {
return sendGroupProto ( numbers , proto ) . then ( function ( ) {
return proto . group . id ;
} ) ;
}
}
self . addNumberToGroup = function ( groupId , number ) {
var proto = new textsecure . protobuf . PushMessageContent ( ) ;
proto . group = new textsecure . protobuf . PushMessageContent . GroupContext ( ) ;
proto . group . id = toArrayBuffer ( groupId ) ;
proto . group . type = textsecure . protobuf . PushMessageContent . GroupContext . Type . UPDATE ;
var numbers = textsecure . storage . groups . addNumbers ( groupId , [ number ] ) ;
if ( numbers === undefined )
return new Promise ( function ( resolve , reject ) { reject ( new Error ( "Unknown Group" ) ) ; } ) ;
proto . group . members = numbers ;
return sendGroupProto ( numbers , proto ) ;
}
self . setGroupName = function ( groupId , name ) {
var proto = new textsecure . protobuf . PushMessageContent ( ) ;
proto . group = new textsecure . protobuf . PushMessageContent . GroupContext ( ) ;
proto . group . id = toArrayBuffer ( groupId ) ;
proto . group . type = textsecure . protobuf . PushMessageContent . GroupContext . Type . UPDATE ;
proto . group . name = name ;
var numbers = textsecure . storage . groups . getNumbers ( groupId ) ;
if ( numbers === undefined )
return new Promise ( function ( resolve , reject ) { reject ( new Error ( "Unknown Group" ) ) ; } ) ;
proto . group . members = numbers ;
return sendGroupProto ( numbers , proto ) ;
}
self . setGroupAvatar = function ( groupId , avatar ) {
var proto = new textsecure . protobuf . PushMessageContent ( ) ;
proto . group = new textsecure . protobuf . PushMessageContent . GroupContext ( ) ;
proto . group . id = toArrayBuffer ( groupId ) ;
proto . group . type = textsecure . protobuf . PushMessageContent . GroupContext . Type . UPDATE ;
var numbers = textsecure . storage . groups . getNumbers ( groupId ) ;
if ( numbers === undefined )
return new Promise ( function ( resolve , reject ) { reject ( new Error ( "Unknown Group" ) ) ; } ) ;
proto . group . members = numbers ;
return makeAttachmentPointer ( avatar ) . then ( function ( attachment ) {
proto . group . avatar = attachment ;
return sendGroupProto ( numbers , proto ) ;
} ) ;
}
self . leaveGroup = function ( groupId ) {
var proto = new textsecure . protobuf . PushMessageContent ( ) ;
proto . group = new textsecure . protobuf . PushMessageContent . GroupContext ( ) ;
proto . group . id = toArrayBuffer ( groupId ) ;
proto . group . type = textsecure . protobuf . PushMessageContent . GroupContext . Type . QUIT ;
var numbers = textsecure . storage . groups . getNumbers ( groupId ) ;
if ( numbers === undefined )
return new Promise ( function ( resolve , reject ) { reject ( new Error ( "Unknown Group" ) ) ; } ) ;
textsecure . storage . groups . deleteGroup ( groupId ) ;
return sendGroupProto ( numbers , proto ) ;
}
return self ;
} ( ) ;