lines 1-8
Constants for every byte we will touch
.equ INSTRUCTION_DATA_LEN, 0x2868.equ INSTRUCTION_DATA, 0x2870.equ ALLOWED_PUBKEYS, 0x2871.equ ACCT0_IS_SIGNER, 0x0009.equ ACCT0_PUBKEY_0, 0x0010.equ ACCT0_PUBKEY_1, 0x0018.equ ACCT0_PUBKEY_2, 0x0020.equ ACCT0_PUBKEY_3, 0x0028Eight constants this time because signer_allowlist reads more pieces of the input region than slippage. The big additions are the is_signer flag byte and the signer's 32-byte pubkey, split into four 8-byte chunks.
INSTRUCTION_DATA_LEN = 0x2868 and INSTRUCTION_DATA = 0x2870 are the standard offsets for any guard with ONE account that holds no data (the per-account region takes 0x2868 bytes, then the ix metadata follows). ALLOWED_PUBKEYS = 0x2871 is exactly one byte past INSTRUCTION_DATA because the ix data layout is [u8 count][32 bytes * count]: one count byte, then count contiguous 32-byte pubkeys.
Why ACCT0_IS_SIGNER = 0x0009? The first 8 bytes of the input region are the u64 account count. Byte 8 is the dup tag (0xFF for a fresh account, otherwise the index of an earlier duplicate). Byte 9 is is_signer. That is exactly where 0x09 comes from. The runtime writes 1 to this byte if and only if the account actually signed the transaction (the signature check happens BEFORE the program runs; this byte is the result the runtime leaves for us).
Why ACCT0_PUBKEY_0..3 at 0x0010, 0x0018, 0x0020, 0x0028? After byte 9 (is_signer) come is_writable (10), executable (11), and 4 bytes of alignment padding (12-15). The 32-byte pubkey starts at byte 16 (0x10). 32 bytes is four u64 chunks of 8 bytes each, so they sit at 16, 24, 32, 40 (which is 0x10, 0x18, 0x20, 0x28). We load all four into registers up front so the inner loop is register-vs-memory, not memory-vs-memory.