NodeCrypto Help

Built-in Script Overview

The built-in script language is a deterministic, statically typed Python subset designed for expressing data-dependent glue logic (conditional branches, bounded loops, custom framing, and helper functions) over bytes, int, bool, and string values inside the Script node.

Read-Only Inputs bytes · int · bool · str Script Node Evaluator Static Type Check · Bounded Loops 24 Built-in Functions · No I/O Output Ports Definitely Assigned

Cryptographic primitives belong in dedicated cipher, hash, MAC, KDF, and signature nodes; the Script node handles the byte-level plumbing between them. It is executed by NodeCrypto's own interpreter (not a general Python runtime), guaranteeing identical, reproducible results across the Web app, Desktop app, CLI, and API Container.

Design Principles

Script Node Structure

ComponentDescription
Input PortsEach input port has a unique identifier (id / display name) and a static data type (bytes, int, bool, or string). Every added input port is required.
Output Ports0 or more output ports, each with a unique identifier and a static data type (bytes, int, bool, or string).
CodeScript source code (up to 64 KiB).

Because port names serve directly as variable names inside the script, every port name must follow the identifier rules, must not collide with reserved keywords or built-in function names, and must be unique across all ports on the node. Neither any nor set ports are allowed on a Script node.

Input and Output Port Binding

Execution Lifecycle

  1. When all connected input ports have values ready, the Script node runs.
  2. Top-level statements execute sequentially from top to bottom.
  3. If execution reaches the end normally, the values held in the output variables are emitted on their corresponding output ports.
  4. If fail(code, message) is called, a runtime error occurs, or a resource limit is exceeded, execution halts immediately, no partial outputs are emitted, and the node enters an ERROR state (see Errors and Resource Limits).

Using the Code Editor

The first tab of the Script node's Properties window is the code editor; input and output ports are managed in the Ports tab (or directly on the node card). If static checking finds an error, the editor highlights the line:column location with the diagnostic message and prevents saving until resolved.

Verified Examples

Every example below is verified against the built-in script evaluator. Byte inputs and outputs are shown in hexadecimal.

CMAC Subkey Derivation (Conditional Branching)

Input l: bytes (AES encryption of the 16-byte zero block), outputs k1: bytes and k2: bytes. For input 7df76b0c1ab899b33e42f047b91b546f, k1 is fbeed618357133667c85e08f7236a8de and k2 is f7ddac306ae266ccf90bc11ee46d513b (RFC 4493 test vector).

def dbl(x: bytes) -> bytes:
    rb = h"00" * (len(x) - 1) + (h"87" if len(x) == 16 else h"1b")
    r = x << 1
    if x[0] & 0x80 != 0:
        r ^= rb
    return r

k1 = dbl(l)
k2 = dbl(k1)

Counter Block Sequence (Lists and Loops)

Inputs seed: bytes and n: int, output out: bytes. When seed is aa and n is 3, produces the concatenation of aa00000000, aa00000001, and aa00000002.

parts: list[bytes] = []
for i in range(n):
    parts += [seed + to_bytes(i, 4)]
out = concat(parts)

Length Validation and Tuple Unpacking

Input data: bytes, outputs head: bytes and body: bytes. Splits the first 4 bytes as the header and the remainder as the body. When data is 0102030405, head is 01020304 and body is 05.

def split2(b: bytes, n: int) -> tuple[bytes, bytes]:
    if len(b) < n:
        fail("DATA_TOO_SHORT", "data is shorter than the header")
    return b[:n], b[n:]

head, body = split2(data, 4)

Passing a 1-byte input 01 to the same script raises DATA_TOO_SHORT and puts the node into an error state:

def split2(b: bytes, n: int) -> tuple[bytes, bytes]:
    if len(b) < n:
        fail("DATA_TOO_SHORT", "data is shorter than the header")
    return b[:n], b[n:]

head, body = split2(data, 4)

DES Key Odd Parity Adjustment (Byte Iteration)

Input key: bytes, output fixed: bytes. Sets the least significant bit of each byte so that every byte has odd parity. For input 0022ff00, outputs 0123fe01.

out: list[int] = []
for v in key:
    ones = 0
    for s in range(1, 8):
        ones += (v >> s) & 1
    out += [(v & 0xFE) | (1 - ones % 2)]
fixed = from_ints(out)

Custom Validation Error with Formatted Message (f-string)

Input key: bytes, output ok: bytes. Aborts with a descriptive error message when key is not 16 bytes long.

if len(key) != 16:
    fail("BAD_KEY_LENGTH", f"key must be 16 bytes, got {len(key)} ({key:x})")
ok = key

Further Reading