### Table of Contents

# OCM VM basics

The OCM bytecode machine is an interpreter for a stack based language. That means that the operands are pushed on a stack first, than the operation is encoded that takes the operands from the stack and puts the result back on the stack. Some typical stack-based languages include RPN calculators, PostScript, Forth and the Java VM. These are specific properties of the OCM machine:

- It has 256 global variables that are addressed using a single byte.
- Entry 252 (0xFC): blob with 8 bytes created from gettimeofday
- Entry 253 (0xFD): blob with 1024 bytes: function pointers for byte codes (patched by interpreter extensions)
- Entry 254 (0xFE): shortint, hiword/loword are major/minor OCM machine version (3.3 for OpenMG 3.4)
- Entry 255 (0xFF): shortint, in OpenMG 3.4: constant 1

- It has a hash table for further global variables that is indexed by a 32 bit number.
- It has a second, alternat stack. This stack is used to save context information for call/return, but also provides operands to certain instructions or can be used as general purpose storage. As it is used for saving the return context, add the end of a code block you must not have anything left on the alternate stack that was not there at the beginning.
- The interpreter can do simple multithreading
- The interpreter has a Stream RNG to decode the instructions (although instruction decoding is initially off)
- The interpreter has a User RNG with a 63 byte state (totally seperate from the stream RNG!)
- It provides a "backdoor" in that you can load native x86 code and execute it.

# OCM Datatypes

Small numbers are a value type, whereas all other types are reference types, i.e. the values are merely references to reference counted objects. The term *object* means the thing the reference points to. Reference counting can be disabled on individual objects, making the permanent.

Small numbers are stored directly in the stack. Other objects are accessed through an intermediate data structure (handle) that points to the object. The value on the stack then is a pointer to the handle, shifted by two bits to the right. The highest two bits contain the type.

struct stack_value { union { unsigned int value : 30; void *handle_div_4; }; unsigned int type : 2; }; struct bigint_handle { uint8_t refcount; uint8_t is_negative; uint16_t len_in_32bitwords; uint32_t payload[0]; // Variable-length-array }; struct blob_handle { uint8_t refcount; uint8_t heap_allocated; uint8_t unknown; uint8_t zero; // Location of data pointer for 0 byte blocks. uint32_t length; void *data; }; struct array_handle { uint8_t refcount; uint8_t unused; uint16_t nr_elements; stack_value data[0]; // Variable length array, entries are handles/smallints };

## Small numbers (tag 0): signed 16 bit numbers

## Large integers (tag 1): arbitraty precision integers

Serialization format: Length followed by two's complement little endian representation. The length is according to ASN.1 lengths: Length is directly encoded as one byte for lengths 0..127. A length encoding starting with 128 is invalid (would mean unspecified). If the first byte of the length is above 128, subtract 128 and take that many bytes. They make up a big-endian unsigned integer.

## Binary blobs (tag 2)

Serialization format: Length followed by the bytes. Length is encoded as for the integers.

## Array (tag 3): An heterogenous array of OCM objects (may contain arrays)

Serialization format: ASN.1 heterogenous sequence

# OCM Opcodes

## Opcodes 00..0F

#### Opcode 00: NOP

does nothing

#### Opcode 01: Immediate byte

immediate data: 1 byte (plaintext, even if OCM code encryption is enabled)

effect: pushes the unsigned 8 bit value of the immediate operand to the stack as small number

#### Opcode 02: Immediate word

immediate data: 1 16-bit-word (plaintext, even if OCM code encryption is enabled)

effect: pushes the signed 16 bit value of the immediate operand to the stack as small number

note: This is used to set up a new decryption key before a 0x73 (Set initial bytecode decryption key in the interpreter) instruction.

#### Opcode 03: Immediate BigInt

immediate data: 1 big int (plaintext, even if OCM code encryption is enabled)

effect: pushes the big int onto stack (after deserialization)

#### Opcode 04: Immediate Blob

immediate data: 1 blob (plaintext, even if OCM code encryption is enabled)

effect: pushes the blob onto stack (after deserialization)

#### Opcode 05: Duplicate Top-Of-Stack

stack input: one value of any type

effect: leaves the input on the stack and pushes a (shallow) copy

#### Opcode 06: Duplicate if not Zero

stack input: one value of any type

effect: duplicates the value like opcode 05, unless it is zero stored as a small int. In that case: no effect

#### Opcode 07: Pop

stack input: one value of any type

effect: the top-of-stack value is deleted. If the stack would get empty, a small int zero is pushed.

#### Opcode 08: Pop & Delete

stack input: one value of any type

effect: Like Pop, but instead of just dropping the reference count for references, the object gets deleted at once. Mostly useful for permanent objects.

#### Opcode 09: Exchange

effect: exchanges top of stack with next-to-top-of-stack

#### Opcode 0A: Next To Top

effect: pushes a copy of the next-to-top value.

PostScript equivalent: "1 index"

#### Opcode 0B: Fetch from Somewhere in Stack

stack input: an index into the stack (call it n); must be small integer and > 0

effect: pushes a copy of the value at n below the input operand. So "Immediate 1;FetchStack" is the same as "Duplicate" and "Immediate 2;FetchStack" is the same as "NextToTop".

PostScript equivalent: "1 sub index"

#### Opcode 0C: Move Top-2 to Top

effect: The value at Top-2 gets moved to top of stack, top of stack becomes top-1 and top-1 is moved to top-2

PostScript equivalent: "3 -1 roll"

#### Opcode 0D: Move Any to Top

stack input: in index into the stack (call it n); must be small integer and > 1

effect: moves the n-th operand below the input operand n to top of stack, shifting everything inbetween downwards. "Immediate 2;MoveToTop" is the same as "Exchange".

PostScript equivalent: "-1 roll"

#### Opcode 0E: Set in Big dictionary

stack input: value (any type, next-to-top); Key (blob of 4 bytes at top of stack)

effect: Adds/Updates an entry in the user dictionary.

#### Opcode 0F: Set in Any Dictionary

stack input: value (any type, next-to-top); Key (blob of 4 bytes OR small int at top of stack)

effect: If top of stack is a small int, the value is stored in the system dictionary at the given index. Must be below 0x100. If top of stack is a blob, like SetInUserDict.

## Opcodes 10..1F

#### Opcode 10: Get from dictionary

stack input: dictionary key (either nonnegative smallint < 0x100 or 4 byte blob)

effect: Looks up the given key in the system dictionary (if a small int) or the user dictionary otherwise. OCM exception gets thrown if the key is not found

stack output: the result of the dictionary lookup

#### Opcode 11: Add Small Ints

stack input: smallint a (next to top); smallint b (top of stack)

stack output: smallint containing a+b

#### Opcode 12: Subtract Small Ints

stack input: smallint a (next to top); smallint b (top of stack)

stack output: smallint containing a-b

#### Opcode 13: Multipy Small Ints

stack input: smallint a (next to top); smallint b (top of stack)

stack output: smallint containing lowest 16 bits of a*b

#### Opcode 14: Divide Small Ints

stack input: smallint a (next to top); smallint b (top of stack)

stack output: smallint containing a/b

#### Opcode 14: Divide and Modulus of Small Ints

stack input: smallint a (next to top); smallint b (top of stack)

stack output: smallint containing a/b (next to top); smallint containing a%b (top of stack)

#### Opcode 16: Modulus of Small Ints

stack input: smallint a (next to top); smallint b (top of stack)

stack output: smallint containing a%b

#### Opcode 17: Xor Small Ints

stack input: smallint a (next to top); smallint b (top of stack)

stack output: smallint containing a ^ b

#### Opcode 18: And Small Ints

stack input: smallint a (next to top); smallint b (top of stack)

stack output: smallint containing a & b

#### Opcode 19: Or Small Ints

stack input: smallint a (next to top); smallint b (top of stack)

stack output: smallint containing a | b

#### Opcode 1A: Bitwise Negate Small Int

stack input: smallint a

stack output: smallint containing ~a

#### Opcode 1B: Shift Left Small Int

stack input: smallint a (next to top); smallint count (top of stack)

stack output: smallint containing a « count

#### Opcode 1C: Shift Right Small Int

stack input: smallint a (next to top); smallint count (top of stack)

stack output: smallint containing ( (unsigned)a) » count

#### Opcode 1D: Shift Right Arithmetic Small Int

stack input: smallint a (next to top); smallint count (top of stack)

stack output: smallint containing a » count

#### Opcode 1E: Compare Small Ints for Greater

stack input: smallint a (next to top); smallint b (top of stack)

stack output: smallint containing 1 if a > b, 0 otherwise

#### Opcode 1F: Compare Small Ints for Less

stack input: smallint a (next to top); smallint b (top of stack)

stack output: smallint containing 1 if a < b, 0 otherwise

## Opcodes 20..2F

#### Opcode 20: Compare Small Ints for equal

stack input: smallint a (next to top); smallint b (top of stack)

stack output: smallint containing 1 if a == b, 0 otherwise

#### Opcode 21: Test for Small Int Zero

stack input: object of any type (maybe only smallint intended)

stack output: 1 if object has type smallint and is zero

#### Opcode 22: Add DWORDs

stack input: small/big int a (next to top); small/big int b (top of stack)

stack output: 32 bit bigint containing a+b

note: DWORD instructions only use the 32 least significant bits in bigint input operands, and samllint operands are treated as unsigned for unknown reasons. All arithmetic is unsigned. As bigints are in sign/magnitude representation, the input sign is ignored for bigints, but not for small ints that are two's complement. But do not use the function with negative inputs unless you wrote the OCM bytecode interpreter, because the sign of the output is undefined in that case (unless you know the internals of the interpreter, that is)

#### Opcode 23: Subtract DWORDs

stack input: small/big int a (next to top); small/big int b (top of stack)

stack output: 32 bit bigint containing a-b

note: See Opcode 22 for important notes on DWORD instructions.

#### Opcode 24: Multiply DWORDs

stack input: small/big int a (next to top); small/big int b (top of stack)

stack output: 32 bit bigint containing a*b (low order 32 bits)

note: See Opcode 22 for important notes on DWORD instructions.

#### Opcode 25: Divide DWORDs

stack input: small/big int a (next to top); small/big int b (top of stack)

stack output: 32 bit bigint containing a/b

note: See Opcode 22 for important notes on DWORD instructions.

#### Opcode 26: Division and Modulus of DWORDs

stack input: small/big int a (next to top); small/big int b (top of stack)

stack output: 32 bit bigint containing a/b (next-to-top); 32 bit bigint containing a%b (top of stack)

note: See Opcode 22 for important notes on DWORD instructions.

#### Opcode 27: Modulus of DWORDs

stack input: small/big int a (next to top); small/big int b (top of stack)

stack output: 32 bit bigint containing a%b

note: See Opcode 22 for important notes on DWORD instructions.

#### Opcode 28: Xor DWORDs

stack input: small/big int a (next to top); small/big int b (top of stack)

stack output: 32 bit bigint containing a ^ b

note: See Opcode 22 for important notes on DWORD instructions.

#### Opcode 29: And DWORDs

stack input: small/big int a (next to top); small/big int b (top of stack)

stack output: 32 bit bigint containing a & b

note: See Opcode 22 for important notes on DWORD instructions.

#### Opcode 2A: Or DWORDs

stack input: small/big int a (next to top); small/big int b (top of stack)

stack output: 32 bit bigint containing a | b

note: See Opcode 22 for important notes on DWORD instructions.

#### Opcode 2B: Bitwise Not DWORD

stack input: small/big int a (top of stack)

stack output: 32 bit bigint containing ~a

note: See Opcode 22 for important notes on DWORD instructions.

#### Opcode 2C: Shift Left DWORD

stack input: small/big int a (next to top); small/big int count (top of stack)

stack output: 32 bit bigint containing a « count

note: See Opcode 22 for important notes on DWORD instructions.

#### Opcode 2D: Shift Right DWORD

stack input: small/big int a (next to top); small/big int count (top of stack)

stack output: 32 bit bigint containing a » count

note: See Opcode 22 for important notes on DWORD instructions.

#### Opcode 2E: Compare DWORDs for Less

stack input: small/big int a (next to top); small/big int b (top of stack)

stack output: smallint containing 1 if a < b; 0 otherwise

note: See Opcode 22 for important notes on DWORD instructions.

#### Opcode 2F: Compare DWORDs for Greater

stack input: small/big int a (next to top); small/big int b (top of stack)

stack output: smallint containing 1 if a > b; 0 otherwise

note: See Opcode 22 for important notes on DWORD instructions.

## Opcodes 30..3F

#### Opcode 30: Compare DWORDs for Equality

stack input: small/big int a (next to top); small/big int b (top of stack)

stack output: smallint containing 1 if a == b; 0 otherwise

note: See Opcode 22 for important notes on DWORD instructions.

#### Opcode 31: Execute

stack input: binary blob containing bytecode

effect: executes the code from the binary blob, continuing after the Execute instruction after the end of the block has been reached.

note: The current execution context is saved on the alternate stack. The blob must not leave something behind on the alternate stack or bad things will happen. The blob also shouldn't try to access the context information on the alternate stack, as it might contain arbitrary 32 bit data that can not be validly interpreted as OCM language objects. Of course the standard stack might be altered by the code in the subblock.

PostScript equivalent: "exec"

#### Opcode 32: If/Else

stack input: selector (smallint at second to top of stack), blob for the true case (next to top), blob for the false case (top of stack)

effect: if the selector is not zero, the true blob is executed (as in Opcode 31), otherwise the false blob is executed.

#### Opcode 33: While

stack input: condition flag (smallint)

**alternate** stack input: blob to execute (not removed by this instruction)

effect: if the condition flag is not zero, the blob at the top of the alternate stack is executed. After execution, the while instruction is restarted, examining the value now at the top of the stack.

note: The blob reference on the alternate stack is **not** removed by this instruction, just the condition flag on the standard stack.

#### Opcode 34: Push to alternate stack

stack input: value of any type

**alternate** stack output: that value of any type

effect: The value is moved from the standard stack to the alternate stack

#### Opcode 35: Pop from alternate stack

**alternate** stack input: value of any type

stack output: that value

effect: The value is moved from the alternate stack to the standard stack

#### Opcode 36: Peek alternate stack

**alternate** stack input: value of any type (not removed by this instruction)

stack output: that value

effect: The value is **copied** from the alternate stack to the standard stack

#### Opcode 37: Push 0

stack output: smallint containing 0

#### Opcode 38: Push 1

stack output: smallint containing 1

#### Opcode 39: Push 2

stack output: smallint containing 2

#### Opcode 3A: Push 3

stack output: smallint containing 3

#### Opcode 3B: Push 4

stack output: smallint containing 4

#### Opcode 3C: Push 5

stack output: smallint containing 5

#### Opcode 3D: Push 6

stack output: smallint containing 6

#### Opcode 3E: Push 7

stack output: smallint containing 7

#### Opcode 3F: Push 8

stack output: smallint containing 8

## Opcodes 40..4F

#### Opcode 40: Push 9

stack output: smallint containing 9

#### Opcode 41: Push -1

stack output: smallint containing -1

#### Opcode 42: Push -2

stack output: smallint containing -2

#### Opcode 43: Push -3

stack output: smallint containing -3

#### Opcode 44: Test Small Int Positive

stack input: smallint a

stack ouput: smallint 1 if a > 0, smallint 0 else

#### Opcode 45: Test Small Int Negative

stack input: smallint a

stack ouput: smallint 1 if a < 0, smallint 0 else

#### Opcode 46: Test Small Int for Zero

stack input: smallint a

stack ouput: smallint 1 if a == 0, smallint 0 else

note: in contrast to Opcode 21 "Test for Small Int Zero", this opcode has undefined behaviour of the operand is not a small integer.

#### Opcode 47: Duplicate second-to-top

effect: pushes a copy of the second-to-top (the third value if you call top-of-stack the first one) to the standard stack.

PostScript equivalent: "2 index"

#### Opcode 48: Duplicate third-to-top

effect: pushes a copy of the third-to-top (the fourth value if you call top-of-stack the first one) to the standard stack.

PostScript equivalent: "3 index"

#### Opcode 49: Duplicate fourth-to-top

effect: pushes a copy of the fourth-to-top (the 5th value if you call top-of-stack the first one) to the standard stack.

PostScript equivalent: "4 index"

#### Opcode 4A: Duplicate 5th-to-top

effect: pushes a copy of the 5th-to-top (the 6th value if you call top-of-stack the first one) to the standard stack.

PostScript equivalent: "5 index"

#### Opcode 4B: Move Top-3 to top

effect: The value at Top-3 gets moved to top of stack, top of stack becomes top-1 and so on.

PostScript equivalent: "4 -1 roll"

#### Opcode 4C: Move Top-4 to top

effect: The value at Top-4 gets moved to top of stack, top of stack becomes top-1 and so on.

PostScript equivalent: "5 -1 roll"

#### Opcode 4D: Move Top-5 to top

effect: The value at Top-5 gets moved to top of stack, top of stack becomes top-1 and so on.

PostScript equivalent: "6 -1 roll"

#### Opcode 4E: Increment Small Int

stack input: smallint a

stack ouput: smallint (a+1)

#### Opcode 4F: Decrement Small Int

stack input: smallint a

stack output: smallint (a-1)

## Opcodes 50..5F

#### Opcode 50: Convert to signed number

stack input: value *a* that is not an array

stack output: *a* if a is numeric (smallint or bigint). If *a* is a blob, is is read as a two's complement signed big-endian number and returned in a bigint.

#### Opcode 51: Convert to unsigned number

stack input: value *a* that is not an array

stack output: *a* if a is numeric (smallint or bigint). If *a* is a blob, is is read as an unsigned big-endian number and returned in a bigint.

note: Negative smallints or bigints are unchanged by this operation. Compare opcode 53 "Make operand unsigned".

#### Opcode 52: Make blob

stack input: value *a* that is not an array

stack output: If the input is a blob, it remains unchanged. Otherwise, it is returned as two's complement big-endian number in a blob.

#### Opcode 53: Make operand unsigned

stack input: numeric value *a*

stack output: A numeric value that results from interpreting the bits in *a* as unsigned number. I.e. smallints 0..32767 are returned unchanged. smallints -1..-32768 are converted to bigints 65536..32768 respsctively. Negative big-ints are sign-extended to whole bytes and the resulting value is treated as unsigned value

#### Opcode 54: Truncate to Small Int

stack input: numeric value *a*

stack output: smallints stay unchanged. The low 16 bits of the absolute value are returned for bigints, so unless you know what you are doing, only use this instruction for the range 0..32767

#### Opcode 55: Pack to Array

stack input: *n* value of any type; smallint *n* (at top of stack)

stack output: (reference to) a newly created array containing the *n* elements from the stack below the count itself

#### Opcode 56: Unpack Array

stack input: an array of *n* elements

stack output: *n* values of any type (the array element); smallint *n* (count of elements; at top of stack)

#### Opcode 57: Array Length

stack input: an array with *n* elements

stack output: smallint *n*

#### Opcode 58: Insert to Array

stack input: *entry* (any type, second to top); an array (next to top); *index* (small or big int at top of stack)

stack output: A (reference to a) copy of the array with the new element *entry* inserted before the *index*'th element (moving all elements after the inserted one position to the end of the array)

#### Opcode 59: Delete from Array

stack input: an array (next to top); *index* (small or big int at top of stack)

stack output: A (reference to a) copy of the array with the element at position *index* removed (and all further elements moved one position to the front)

#### Opcode 5A: Get Array Element

stack input: (reference to) an array (next to top); smallint *k* (top of stack)

stack output: The *k*'th element of the array.

#### Opcode 5B: Set Array Element

stack input: value *x* of any type (second to top); (reference to) an array (next to top); smallint *k* (at top)

stack output: The *k*'th element of the array before replacing it.

effect: The *k*'th element of the array is replaced by *x*.

note: This operation does **not** copy the array, so the element changes globally.

#### Opcode 5C: Create Array

stack input: *n* (smallint at top of stack)

stack output: A newly allocated array of *n* elements. All elements are initialized with smallint zero.

#### Opcode 5D: Encode ASN.1

stack input: value to encode (any type)

stack output: A blob that contains the ASN.1 representation of the value.

note: Encoding uses universal tags as follows:

- smallints and bigints are encoded as INTEGER (ASN.1 tag 0x02)
- blobs are encoded as OCTET STRING (ASN.1 tag 0x04)
- arrays are encoded as SEQUENCE (ASN.1 tag 0x30), the sequence is always encoded as unknown-length and double-zero-terminated.

#### Opcode 5E: Catenate to Sequence

stack input: *n* blobs (should contain ASN.1 encoded data, first element pushed first, last element next-to-top); *n* (smallint at top of stack)

stack output: a blob containing an ASN.1 sequence of the *n* encoded objects.

note: The output is just 0x30 (SEQUENCE); 0x80 (unknown length); catenation of all blobs; 0x00; 0x00

#### Opcode 5F: Decode ASN.1

stack input: a blob containing an ASN.1 encoded object.

stack ouput: the decoded object.

note: The following objects are recognized:

- Tag 0x01 (BOOLEAN) → decoded as smallint 0 or 1
- Tag 0x02 (INTEGER) → Values 0..32767 as smallint; other values as bigint
- Tag 0x17, Tag 0x18 (UTCTime, GeneralizedTime) → bigint containing a unix timestamp (seconds since 1.1.1970, 00:00 GMT)
- all other univesal tags with composed object bit clear (0x03-0x16;0x19-0x1F) → decoded as blob
- Tag 0x30, Tag 0x31 (SEQUENCE, SET) → decoded as array
- all context-specific tags (0x80..0xBF) → decoded as blob

## Opcodes 60..6F

#### Opcode 60: Enclose Smallint

stack input: A smallint

stack output: A blob containing the little-endian (host byte order) representation of the smallint

Note: the blob that gets returned is non-refcounted and lives until explicit destruction (for example by opcode 08)

#### Opcode 61: Get Enclosed Smallint

stack input: A blob that encloses a small integer, created by opcode 60

stack output: The enclosed small integer

#### Opcode 62: Get Significant Bits

stack input: Object of any type

stack ouput: Significant bit in that object. For smallints and bigints its the minimal number of bits to represent the absolute value of that number, for blobs the number of bytes multiplied by 8 and for arrays the sum of the number of significant bits of all entries.

#### Opcode 63: Immediate Crypted Byte

immediate data: 1 byte (encrypted if OCM code encryption is enabled)

effect: pushes the unsigned 8 bit value of the immediate operand to the stack as small number

note: Is often used to refer to the dictionary index where the data is stored.

#### Opcode 64: Immediate Crypted Word

immediate data: 1 16-bit-word (encrypted if OCM code encryption is enabled)

effect: pushes the signed 16 bit value of the immediate operand to the stack as small number

#### Opcode 65: Immediate Crypted BigInt

immediate data: 1 big int (encrypted if OCM code encryption is enabled)

effect: pushes the big int onto stack (after deserialization)

note: If the OCM module uses the DWORD-based decryptor (it doesn't start with 03 01 in that case, we did not encounter such a module yet), it is important to know that the immediate arg is decrypted in three parts: (1) initial length byte, (2) extra length bytes, optional, (3) data bytes.

#### Opcode 66: Immediate Crypted Blob

immediate data: 1 blob (encrypted if OCM code encryption is enabled)

effect: pushes the blob onto stack (after deserialization)

note: If the OCM module uses the DWORD-based decryptor (it doesn't start with 03 01 in that case, we did not encounter such a module yet), it is important to know that the immediate arg is decrypted in three parts: (1) initial length byte, (2) extra length bytes, optional, (3) data bytes.

#### Opcode 67: Start Threads

stack input: common thread arg (any type); *n* blobs containing byte code; smallint *n* (at top of stack)

effect: Starts pseudo-parallel execution of all n blobs. Execution of the main code (that invoked this opcode) stops until all threads are finished or the threaded evaluation mode is cancelled. All threads have their own stack, each containing just the common arg. Also every thread has its private alternate stack.

#### Opcode 68: Set Time Slice Length

stack input: smallint or bigint *len*

effect: Sets the time slice length for this subthread to *len*. That is the number of bytecode instructions executed for this thread until execution continues with another thread. The current timeslice is unmodified, it just affects the following slices.

#### Opcode 69: Cancel Threaded Execution

effect: Aborts executing of all subthreads and immediately continues the main thread past its start threads opcode.

#### Opcode 6A: Push To Main Thread Stack

stack input: a value of any type

effect: Moves that value to the stack of the currently suspended main thread.

note: This opcode does only make sense in subthreads.

#### Opcode 6B: Pop From Main Thread Stack

effect: Pops the top value from the stack of the suspended main thread

stack output: the value removed from the suspended main thread's stack.

note: This opcode does only make sense in subthreads.

#### Opcode 6C: Copy From Main Thread Stack

effect: Copies the top value from the stack of the suspended main thread

stack output: the value at the top of the suspended main thread's stack.

note: This opcode does only make sense in subthreads.

#### Opcode 6D: gettimeofday

stack output: seconds since midnight (tv_sec) as bigint (next to top); microseconds within current second (tv_usec) as bigint (top of stack)

#### Opcode 6E: mktime

stack input: 6 smallint or bigint values in the following order: seconds, minutes, hours, day (1-based), month (0-based), year (top of stack)

stack output: the corresponding unix timestamp

#### Opcode 6F: localtime

stack input: a small/big int containing a unix timestamp

stack output: 6 smallints in this order: seconds, minutes, hours, day (1-based), month (0-based), year (top of stack)

## Opcodes 70..7F

#### Opcode 70: Get Type

stack input: object of any type

stack output: The type tag of that object (see top of the page)

#### Opcode 71: Get Random Number

stack input: smallint *n* of values to skip

stack output: The number generated by the user RNG after skipping *n* values.

#### Opcode 72: Set User RNG Autoskip

stack input: smallint *n*

effect: Enables autoskipping, i.e. advancing the user RNG by *n* for every opcode executed. *n*==0 disables it.

#### Opcode 73: Seed and Enable Stream Decryptor

stack input: smallint *n* as 16 bit seed value.

effect: Turn on the Stream RNG that generates a key stream to decode all following instruction.

note: This will indicate that the following bytes are encrypted.

#### Opcode 74: Load Stream Decryptor Table

stack input: A reference to a block of bytes. The size must be a power of 2

effect: Replaces the standard table in the Stream PRNG by the one given as parameter

#### Opcode 75: Load Native Module

stack input: A blob containing a (possibly compressed) module of native code

stack ouput: smallint containing the module handle. (a one-byte number)

effect: The contents of that blob gets loaded into the virtual machine. The first 0x60 bytes of the blob are a header for the module that, amongst other things, contains the name of the module which is used to identify it. The module is decompressed, relocated and the exported names are put into the salwrap global exports table (unless the module is named "bc", in that case, exports are not yet loaded)

#### Opcode 76: Unload native module

stack input: A module handle (as smallint)

stack ouput: 1 if the module had on-demand-exports, 0 otherwise (probably wrong description)

effect: Unloads the given native module. If it is not named "bc", the exports are removed from the global symbol table before unloading the module.

#### Opcode 77: Call a native module

stack input: args for the native module (type(s) module specific); module handle (smallint at top)

stack output: result from the native module (type(s) module specific)

effect: Runs the native code associated with the given module handle. It removes the module handle from the stack before running that module. The module itself can do to the stack whatever it wants.

#### Opcode 78: Run Unloaded Native Module

stack input: possible module args; a blob containing a non-compressed module (at top; like for Opcode 75)

stack output: possible module results

effect: Executes the native code from the blob given as parameter. The blob is relocated and exports are loaded (unless it is a "bc" named blob). As the blob is non-permanent, there better are no exports. The entrypoint is finally called (Like Opcode 77 does for a loaded module)

#### Opcode 79: Get Module Name

stack input: module handle (as smallint)

stack ouput: blob containing name of that module

#### Opcode 7A: Get Module Handle

stack input: blob containing of module name

stack ouput: smallint containing module handle

#### Opcode 7B: Create Module For Blob

stack input: module name (blob next to top); module contents (blob at top)

stack output: smallint containing module handle

Creates an entry in the module list that references the address range of the blob.

#### Opcode 7C: Create Bytecode Module

stack input: module contents (blob); module name (blob at top, optional)

stack output: smallint containing module handle

Copies the blob contents into the interpreter as bytecode module. If top of stack is ⇐ 8 chars, it is treated as a name. Otherwise the standard name "bc" is used instead.

#### Opcode 7D: Run OCM Module

stack input: smallint containing module handle.

effect: the module handle must refer to a module not containing native code, but some byte code. This bytecode is executed (as a subroutine)

note: The ocm module is stored in the global dictionary. This instruction is used to "import" the device.sal library declarations to a programs environment. The ocm module data and the global dictionary reference to it are loaded using the salwrap function setDeviceSal.

#### Opcode 7E: Seed User RNG

stack input: smallint; blob (at top of stack)

effect: uses the smallint and the blob to seed the User PRNG.

#### Opcode 7F: Nop

effect: none

## Opcodes 80..86

#### Opcode 80: unknown purpose

stack input: codenum (smallint)

effect: if codenum is zero, calls a hookable function in salwrap (export 0x68), otherwise does nothing

#### Opcode 81: Pop w/o dropping refcount

stack input: value of any type

effect: removes the value from the stack without adjusting its reference count.

note: is the same as 84

#### Opcode 82: Nop

effect: none

#### Opcode 83: Nop

effect: none

#### Opcode 84: Pop w/o dropping refcount

stack input: value of any type

effect: removes the value from the stack without adjusting its reference count.

note: is the same as 81

#### Opcode 85: Call dictionary proc

stack input: dictionary key (smallint for system dict, 32 bit blob for user dictionary)

effect: Gets the blob at the given dictionary index, as opcode 10 would do too, and then invokes it like opcode 31 would do, but this call opcode is the only possibility to do clean inter-module calls, at only it uses the context (Stream PRNG, OCM header valid for blob) stored in the dict alongside the value.

#### Opcode 86: rdtsc

stack output: a 64 bit bigint containing the result of rdtsc

## Extra opcodes

#### Opcode FB:

complicated calling instruction, probably including stack swapping. Might by something like try/catch

# Documentation for the "extrins" module

Contains long number arithmetic (arbitrary precision). small/bigint indicates parameters that are auto-promoted to bigints if given as smallint. The usual signed interpretation of smallints is used (opposed to dword arithmetic instructions)

A datatype "fuzzed integer" is used in some opcodes. Technically, its just a big int, but semantically, it has been transformed to not have the number directly in core. This transformation is dependent on the modulus in modular artihmetics, so "fuzzed integers" are specific to one modules

## Opcode 0x87..0x8F

#### Opcode 0x87: Add Big Integers

stack input: small/big int *a*; small/big int *b*

stack output: bigint *a* + *b*

#### Opcode 0x88: Subtract Big Integers

stack input: small/big int *a*; small/big int *b*

stack output: bigint *a* - *b*

#### Opcode 0x89: Multiply Big Integers

stack input: small/big int *a*; small/big int *b*

stack output: bigint *a* * *b*

#### Opcode 0x8A: Divide Big Integers

stack input: small/big int *a*; small/big int *b*

stack output: bigint *a* / *b*

#### Opcode 0x8B: Divide and Modulus of Big Integers

stack input: small/big int *a*; small/big int *b*

stack output: bigint *a* % *b*; *a* / *b* (careful, different order than DivMod for smallints and dwords. Somerthing wrong here?)

#### Opcode 0x8C: Modulus of Big Integers

stack input: small/big int *a*; small/big int *b*

stack output: bigint *a* % *b*

#### Opcode 0x8D: Compare Big Integers for Greater

stack input: small/big int *a*; small/big int *b*

stack output: smallint 1 if *a*>*b*, smallint 0 otherwise

#### Opcode 0x8E: Compare Big Integers for Less

stack input: small/big int *a*; small/big int *b*

stack output: smallint 1 if *a*<*b*, smallint 0 otherwise

#### Opcode 0x8F: Compare Big Integers for Equal

stack input: small/big int *a*; small/big int *b*

stack output: smallint 1 if *a*==*b*, smallint 0 otherwise

## Opcode 0x90..0x9F

#### Opcode 0x90: Bitwise XOR Big Integers

stack input: small/big int *a*; small/big int *b*

stack output: bigint *a* & *b*

#### Opcode 0x91: Bitwise AND Big Integers

stack input: small/big int *a*; small/big int *b*

stack output: bigint *a* | *b*

#### Opcode 0x92: Bitwise OR Big Integers

stack input: small/big int *a*; small/big int *b*

stack output: bigint *a* ^ *b*

#### Opcode 0x93: Shift Left Big Integers

stack input: small/big int *a*; DWORD *b*

stack output: bigint *a* « *b*

note: DWORDs means that smallints are treated as unsigned 16 bit values in that case. See Instruction 0x22 for details.

#### Opcode 0x94: Shift Right Big Integers

stack input: small/big int *a*; DWORD *b*

stack output: bigint *a* » *b*

note: DWORDs means that smallints are treated as unsigned 16 bit values in that case. See Instruction 0x22 for details.

#### Opcode 0x95: Add Big Integers (in Modular Arithmetics)

stack input: small/big int *a*; small/big int *b*; small/big int *m*

stack output: bigint *a* + *b* (mod *m*)

#### Opcode 0x96: Subtract Big Integers (in Modular Arithmetics)

stack input: small/big int *a*; small/big int *b*; small/big int *m*

stack output: bigint *a* - *b* (mod *m*)

#### Opcode 0x97: Multiply Big Integers (in Modular Arithmetics)

stack input: small/big int *a*; small/big int *b*; small/big int *m*

stack output: bigint *a* * *b* (mod *m*)

#### Opcode 0x98: Negate Big Integer (in Modular Arithmetics)

stack input: small/big int *a*; small/big int *m*

stack output: bigint -*a* (mod *m*)

#### Opcode 0x99: Reciprocal of Big Integer (in Modular Arithmetics)

stack input: small/big int *a*; small/big int *m*

stack output: bigint (1 / *a*) (mod *m*)

#### Opcode 0x9A: Power of Big Integers (in Modular Arithmetics)

stack input: small/big int *a*; small/big int *e*; small/big int *m*

stack output: bigint (*a* to the *e*'th power (mod *m*) )

#### Opcode 0x9B: Product of Powers of Big Integers (in Modular Arithmetics)

stack input: small/big int *a1*; small/big int *e1*; small/big int *a2*; small/big int *e2*; small/big int *m*

stack output: bigint (*a1* to the *e1*'th power * *a2* to the *e2*'th power (mod *m*) )

note: This is more efficient than using 0x9A twice and then multiply the result with 0x97, but yields the same result.

#### Opcode 0x9C: Root of Big Integer (in Modular Arithmetics)

stack input: small/big int *a*; small/big int *m*

stack output bigint *r* such that *r***r* == *a* (mod *m*), or *r* == 0 if no value satisfies that equation.

#### Opcode 0x9D: Initialize Fuzzing Context

stack input: small/big int *m*

stack ouptut: fuzzing context object for modulus *m*

#### Opcode 0x9E: Fuzz Number

stack input: small/big int *a*; fuzzing context

stack output: fuzzed value of *a*

#### Opcode 0x9F: Unfuzz Number

stack input: fuzzed int *f*; fuzzing context

stack ouput: unfuzzed value of *f*

## Opcode 0xA0..0xAF

#### Opcode 0xA0: Add Fuzzed Numbers (Modular arithmetics)

stack input: fuzzed int *f*; fuzzed int *g*; fuzzing context

stack ouput: fuzzed int *f*+*g* (mod *m* from fuzzing context)

#### Opcode 0xA1: Subtracted Fuzzed Numbers (Modular arithmetics)

stack input: fuzzed int *f*; fuzzed int *g*; fuzzing context

stack ouput: fuzzed int *f*-*g* (mod *m* from fuzzing context)

#### Opcode 0xA2: Multiply Fuzzed Numbers (Modular arithmetics)

stack input: fuzzed int *f*; fuzzed int *g*; fuzzing context

stack ouput: fuzzed int *f***g* (mod *m* from fuzzing context)

#### Opcode 0xA3: Negate Fuzzed Numbers (Modular arithmetics)

stack input: fuzzed int *f*; fuzzing context

stack ouput: fuzzed int -*f* (mod *m* from fuzzing context)

#### Opcode 0xA4: Reciprocal of Fuzzed Number (Modular arithmetics)

stack input: fuzzed int *f*; fuzzing context

stack ouput: fuzzed int 1 / *f* (mod *m* from fuzzing context)

#### Opcode 0xA5: Power of Fuzzed Number (Modular arithmetics)

stack input: fuzzed int *f*; (unfuzzed) small/big int *e*; fuzzing context

stack ouput: fuzzed int *f* to the *e*'th power (mod *m* from fuzzing context)

#### Opcode 0xA6: Product of Powers of Fuzzed Numbers (in Modular Arithmetics)

stack input: fuzzed int *f1*; (unfuzzed) small/big int *e1*; fuzzed int *a2*; (unfuzzed) small/big int *e2*; fuzzing context

stack output: fuzzed int (*f1* to the *e1*'th power * *f2* to the *e2*'th power (mod *m* from fuzzing context) )

note: This is more efficient than using 0xA5 twice and then multiply the result with 0xA2, but yields the same result.

#### Opcode 0xA7: Initialize Power Context

stack input: fuzzed int *base*; DWORD *bits*; DWORD *parts*; fuzzing context

stack output: power context for the given parameters.

note: A power context contains helper data to calculate different powers of the same base in with the same modulus. The power context gets optimized for exponents with approximately *bits* significant bits. The underlying algorithm is a divide-and-conquer algorithm. The number of parts the exponent will be divided to is given in *parts*, with an upper bound of 16.

#### Opcode 0xA8: Calculate Power using Power Context

stack input: small/big int *exp*; power context

stack output: unfuzzed(!) result of *base* (from the context) to the *exp*'th power.

#### Opcode 0xA9: Calculate Product of Powers using Power Contexts

stack input: small/big int *exp1*; power context *ctx1*; small/big int *exp2*; power context *ctx2*

stack output: bigint containing *base1* to the *exp1*'th power multiplied by *base2* to the *exp2*'th power (bases taken from contexts)

note: Does only work if the modulus in *ctx1* und *ctx2* is the same. Otherwise strange things will happen.

#### Opcode 0xAA: Create Mod-P Elliptic Curve Context

stack input: small/big int *p*; small/big int *a*; small/big int *b*

stack output: elliptic curve context describing the elliptic curve with the parameters *a* and *b* in the finite field of modular arithmetics to the base *p*, which should be prime.

#### Opcode 0xAB: Add Points in Mod-P Elliptic Curve

stack input: small/big int *x1*; small/big int *y1*; small/big int *x2*; small/big int *y2*; elliptic curve context

stack output: bigint *xr*; bigint *yr* (such that (*xr*,*yr*) = (*x1*,*y1*)+(*x2*,*y2*))

note: This is about addition within an elliptic curve. This is **not** standard vector addition, it is just called addition, as it has a mathematical similar structure. If you want to understand what is really going on, read an introduction into elliptic curve arithmetics.

#### Opcode 0xAC: Negate in Mod-P Elliptic Curve

stack input: small/big int *x*; small/big int *y*; elliptic curve context

stack output: bigint *x*; bigint -*y* (mod *p* from context)

#### Opcode 0xAD: Multiplication with Scalar in Mod-P Elliptic Curve

stack input: small/big int *n*; small/big int *x*; small/big int *y*; elliptic curve context

stack output: bigint *xres*; bigint *yres*, satisfying (*xres*,*yres*) = *n**(*x*,*y*)

note: This is multiplication with a scalar within an elliptic curve. It is the same as adding up (*x*,*y*) *n* times by elliptic curve addition. It is **not** standard vector multiplication. Especially, the output does not resemble (*n***x*, *n***y*) in any way.

#### Opcode 0xAE: Dual Multiplication with Scalar in Mod-P Elliptic Curve

stack input: small/big int *n1*; small/big int *x1*; small/big int *y1*; small/big int *n2*; small/big int *x2*; small/big int *y2*; elliptic curve context

stack output: bigint *xres*; bigint *yres*, satisfying (*xres*,*yres*) = *n1**(*x1*,*y1*) + *n2**(*x2*,*y2*)

note: This is faster than doing two multiplications with 0xAD and adding with 0xAB, but yields the same result. Notes of that opcodes apply here, too.

#### Opcode 0xAF: Create Mod-P Elliptic Curve Multiplication Context

stack input: small/big int *x*; small/big int *y*; DWORD *bits*; DWORD *parts*; elliptic curve context

stack output: elliptic curve multiplication context to calculate multiples of (*x*,*y*) on the given elliptic curve.

note: An elliptic curve multiplication context contains helper data to calculate different multiples of the same point in with the same modulus. The multiplication context gets optimized for scalar factors with approximately *bits* significant bits. The underlying algorithm is a divide-and-conquer algorithm. The number of parts the scalar factor will be divided to is given in *parts*, with an upper bound of 16.

## Opcode 0xB0..0xC1

#### Opcode 0xB0: Calculate Product using Mod-P Elliptic Curve Multiplication Context

stack input: small/big int *n*; elliptic curve multiplication context

stack output: bigint *x*; bigint *y*: satifying (*x*,*y*) = *n**(*x0*,*y0*) (from the context)

#### Opcode 0xB1: Calculate Sum Of Products using Mod-P Elliptic Curve Multiplication Contexts

stack input: small/big int *n1*; elliptic curve multiplication context *ctx1*; small/big int *n2*; elliptic curve multiplication context *ctx2*

stack output: bigint *x*; bigint *y*: satifying (*x*,*y*) = *n1**(*x1*,*y1*)+*n2**(*x2*,*y2*) (*x1*, *y1*, *x2*, *y2* from the contexts)

note: Does only work if the modulus and the a and b parameters in *ctx1* und *ctx2* is the same. Otherwise strange things will happen.

#### Opcode 0xB2: Create Galois Field (GF) Elliptic Curve Context

stack input: DWORD *n*; DWORD *m*; small/big int *a*; small/big int *b*; (*n* > *m*; *m* > 0)

stack output: GF elliptic curve context describing the elliptic curve with the parameters *a* and *b* in the finite field defined by the irreducible polynomial

#### Opcode 0xB3: Add Points in GF Elliptic Curve

stack input: small/big int *x1*; small/big int *y1*; small/big int *x2*; small/big int *y2*; GF elliptic curve context

stack output: bigint *xr*; bigint *yr* (such that (*xr*,*yr*) = (*x1*,*y1*)+(*x2*,*y2*))

note: This is about addition within an elliptic curve. This is **not** standard vector addition, it is just called addition, as it has a mathematical similar structure. If you want to understand what is really going on, read an introduction into elliptic curve arithmetics.

#### Opcode 0xB4: Negate in GF Elliptic Curve

stack input: small/big int *x*; small/big int *y*; GF elliptic curve context

stack output: bigint *xr*; bigint *yr*, such that (*xr*,*yr*) + (*x*,*y*) results in the point at infinity.

#### Opcode 0xB5: Multiplication with Scalar in GF Elliptic Curve

stack input: small/big int *n*; small/big int *x*; small/big int *y*; GF elliptic curve context

stack output: bigint *xres*; bigint *yres*, satisfying (*xres*,*yres*) = *n**(*x*,*y*)

note: This is multiplication with a scalar within an elliptic curve. It is the same as adding up (*x*,*y*) *n* times by elliptic curve addition. It is **not** standard vector multiplication. Especially, the output does not resemble (*n***x*, *n***y*) in any way.

#### Opcode 0xB6: Dual Multiplication with Scalar in GF Elliptic Curve

stack input: small/big int *n1*; small/big int *x1*; small/big int *y1*; small/big int *n2*; small/big int *x2*; small/big int *y2*; GF elliptic curve context

stack output: bigint *xres*; bigint *yres*, satisfying (*xres*,*yres*) = *n1**(*x1*,*y1*) + *n2**(*x2*,*y2*)

note: This is faster than doing two multiplications with 0xB5 and adding with 0xB3, but yields the same result. Notes of that opcodes apply here, too.

#### Opcode 0xB7: Create GF Elliptic Curve Multiplication Context

stack input: small/big int *x*; small/big int *y*; DWORD *bits*; DWORD *parts*; GF elliptic curve context

stack output: GF elliptic curve multiplication context to calculate multiples of (*x*,*y*) on the given elliptic curve.

note: An elliptic curve multiplication context contains helper data to calculate different multiples of the same point in with the same modulus. The multiplication context gets optimized for scalar factors with approximately *bits* significant bits. The underlying algorithm is a divide-and-conquer algorithm. The number of parts the scalar factor will be divided to is given in *parts*, with an upper bound of 16.

#### Opcode 0xB8: Calculate Product using GF Elliptic Curve Multiplication Context

stack input: small/big int *n*; GF elliptic curve multiplication context

stack output: bigint *x*; bigint *y*: satifying (*x*,*y*) = *n**(*x0*,*y0*) (from the context)

#### Opcode 0xB9: Calculate Sum Of Products using GF Elliptic Curve Multiplication Contexts

stack input: small/big int *n1*; GF elliptic curve multiplication context *ctx1*; small/big int *n2*; GF elliptic curve multiplication context *ctx2*

stack output: bigint *x*; bigint *y*: satifying (*x*,*y*) = *n1**(*x1*,*y1*)+*n2**(*x2*,*y2*) (*x1*, *y1*, *x2*, *y2* from the contexts)

note: Does only work if the polynomial and the a and b parameters in *ctx1* und *ctx2* is the same. Otherwise strange things will happen.

#### Opcode 0xBA: Create Galois Field Efficient Squaring (GFES) Elliptic Curve Context

stack input: DWORD *bits*; small/big int *a*; small/big int *b*;

stack output: GF elliptic curve context describing the elliptic curve with the parameters *a* and *b* in the finite field . An representation of that Galois field is chosen in which squaring is very efficient. More info about that representation to come later.

#### Opcode 0xBB: Add Points in GFES Elliptic Curve

stack input: small/big int *x1*; small/big int *y1*; small/big int *x2*; small/big int *y2*; GFES elliptic curve context

stack output: bigint *xr*; bigint *yr* (such that (*xr*,*yr*) = (*x1*,*y1*)+(*x2*,*y2*))

note: This is about addition within an elliptic curve. This is **not** standard vector addition, it is just called addition, as it has a mathematical similar structure. If you want to understand what is really going on, read an introduction into elliptic curve arithmetics.

#### Opcode 0xBC: Negate in GFES Elliptic Curve

stack input: small/big int *x*; small/big int *y*; GFES elliptic curve context

stack output: bigint *xr*; bigint *yr*, such that (*xr*,*yr*) + (*x*,*y*) results in the point at infinity.

#### Opcode 0xBD: Multiplication with Scalar in GFES Elliptic Curve

stack input: small/big int *n*; small/big int *x*; small/big int *y*; GFES elliptic curve context

stack output: bigint *xres*; bigint *yres*, satisfying (*xres*,*yres*) = *n**(*x*,*y*)

note: This is multiplication with a scalar within an elliptic curve. It is the same as adding up (*x*,*y*) *n* times by elliptic curve addition. It is **not** standard vector multiplication. Especially, the output does not resemble (*n***x*, *n***y*) in any way.

#### Opcode 0xBE: Dual Multiplication with Scalar in GFES Elliptic Curve

stack input: small/big int *n1*; small/big int *x1*; small/big int *y1*; small/big int *n2*; small/big int *x2*; small/big int *y2*; GFES elliptic curve context

stack output: bigint *xres*; bigint *yres*, satisfying (*xres*,*yres*) = *n1**(*x1*,*y1*) + *n2**(*x2*,*y2*)

note: This is faster than doing two multiplications with 0xBD and adding with 0xBB, but yields the same result. Notes of that opcodes apply here, too.

#### Opcode 0xBF: Create GFES Elliptic Curve Multiplication Context

stack input: small/big int *x*; small/big int *y*; DWORD *bits*; DWORD *parts*; GFES elliptic curve context

stack output: GFES elliptic curve multiplication context to calculate multiples of (*x*,*y*) on the given elliptic curve.

note: An elliptic curve multiplication context contains helper data to calculate different multiples of the same point in with the same modulus. The multiplication context gets optimized for scalar factors with approximately *bits* significant bits. The underlying algorithm is a divide-and-conquer algorithm. The number of parts the scalar factor will be divided to is given in *parts*, with an upper bound of 16.

#### Opcode 0xC0: Calculate Product using GFES Elliptic Curve Multiplication Context

stack input: small/big int *n*; GFES elliptic curve multiplication context

stack output: bigint *x*; bigint *y*: satifying (*x*,*y*) = *n**(*x0*,*y0*) (from the context)

#### Opcode 0xC1: Calculate Sum Of Products using GFES Elliptic Curve Multiplication Contexts

stack input: small/big int *n1*; GFES elliptic curve multiplication context *ctx1*; small/big int *n2*; GFES elliptic curve multiplication context *ctx2*

stack output: bigint *x*; bigint *y*: satifying (*x*,*y*) = *n1**(*x1*,*y1*)+*n2**(*x2*,*y2*) (*x1*, *y1*, *x2*, *y2* from the contexts)

note: Does only work if the bit count and the a and b parameters in *ctx1* und *ctx2* is the same. Otherwise strange things will happen.

# Preliminary documentation for "compat" module

This list shows an overview over the opcodes C2..E0 (from compat, a module inside init.ocm). The numbers are **relative** opcode numbers, i.e. the opcode minus the base opcode of C2.

dd 0 (0xc2) ; DATA XREF: initproc:loc_4166r dd offset BCX_00_Subblob ; DATA XREF: initproc+42r ; string index length -> substring Marcus: If length == -1, take until end of blob. dd 1 (0xc3) dd offset BCX_01_Concat ; firstpart secondpart --> concatenated dd 2 (0xc4) dd offset BCX_02_CompareBlob ; blob1 blob2 --> cmpresult ; (lexicographically) dd 3 (0xc5) dd offset BCX_03_CompareN ; blob1 blob2 count --> cmpresult ; (lexicographically, but trimm blob1 and blob2 to count before) dd 4 (0xc6) dd offset BCX_04_IndexBlob ; blob idx --> char_at_idx dd 5 (0xc7) dd offset BCX_05_BlobLen ; blob --> length (16 bit OR bigint) dd 6 (0xc8) dd offset BCX_06_XorBlobs ; blob1 blob2 --> blob1^blob2 ; extends shorter blob with zero bytes dd 7 (0xc9) dd offset BCX_07_XorBlobsRepeating ; blob1 blob2 --> blob1 ^ blob2 ; the shorter blobs gets repeated to reach the length of the longer blob. ; If the length of the longer blob is not evenly divisible by the length of the shorter blob ; --> runtime error dd 8 (0xca) dd offset BCX_08_RepeatNUL ; count --> blob dd 9 (0xcb) dd offset BCX_09_ReplaceSubblob ; bigblob offset newdata --> patchedbigblob dd 0Ah (0xcc) dd offset BCX_0A_FloatAdd ; num1 num2 --> num1+num2 dd 0Bh (0xcd) dd offset BCX_0B_FloatSub ; num1 num2 --> num1-num2 dd 0Ch (0xce) dd offset BCX_0C_FloatMul ; num1 num2 --> num1*num2 dd 0Dh (0xcf) dd offset BCX_0D_FloatDiv ; num1 num2 --> num1/num2 dd 0Eh (0xd0) dd offset BCX_0E_FloatEq ; flt1 flt2 --> flt1==flt2 dd 0Fh (0xd1) dd offset BCX_0F_FloatLt ; flt1 flt2 --> flt2 < flt1 dd 10h (0xd2) dd offset BCX_10_FloatGt ; flt1 flt2 --> flt2 > flt1 dd 11h (0xd3) dd offset BCX_11_FloatToInt ; flt --> int ; Does not handle ints > 32 bits dd 12h (0xd4) dd offset BCX_12_atof ; ascii-blob --> float dd 13h (0xd5) dd offset BCX_13_nop dd 14h (0xd6) dd offset BCX_14_DESSetKey ; keyblob --> scheduleblob dd 15h (0xd7) dd offset BCX_15_DESEncrypt1 ; data keyschedule --> encrypted data dd 16h (0xd8) dd offset BCX_16_DESDecrypt1 ; data keyschedule --> decrypted data dd 17h (0xd9) dd offset BCX_17_DES_ECB_Encrypt ; data keyschedule --> encrypted data dd 18h (0xda) dd offset BCX_18_DES_ECB_Decrypt ; data keyschedule --> decrypted data dd 19h (0xdb) dd offset BCX_19_InitSHA1 ; --> SHA1 state object dd 1Ah (0xdc) dd offset BCX_1A_SHA1AddData ; data length state --> newstate Marcus: I have seen LENGTH being 0, which I can only suppose means that the whole blob DATA is added. dd 1Bh (0xdd) dd offset BCX_1B_SHA1Finish ; state --> hash dd 1Ch (0xde) dd offset BCX_1C_GetPRNGBytes ; count --> blob dd 1Dh (0xdf) dd offset DES_CBC_Encrypt ; data iv keyschedule magic -> data' ; magic must be DES_ECB_Encrypt or DES_ECB_Decrypt opcode as blob dd 1Eh (0xe0) dd offset DES_CBC_Decrypt ; data iv keyschedule magic -> data' ; magic must be DES_ECB_Encrypt or DES_ECB_Decrypt opcode as blob