Swizzer's Sound

Back

2025 GoogleCTFBlur image

记录一下我解的几题。

Crypto#

numerology#

题目给的是个基于Python 3.12的pyc文件,需要反编译一下。PyLingual直接搞出来的长这样

整下来几十个error,不像是能用的样子,扔给Gemini优化一下

task_optimized_by_Gemini.py
# Decompiled with PyLingual (https://pylingual.io)
# Internal filename: ./crypto_numerology.py
# Bytecode version: 3.12.0rc2 (3531)
# Source timestamp: 2025-06-06 16:54:22 UTC (1749228862)

import argparse
import json
import os
import struct
import sys
from pathlib import Path

CHACHA_CONSTANTS = (1634760805, 857760878, 2036477234, 1797285236)
# This global was misplaced inside a function by the decompiler.
# It is used to set the initial constants to zero for the challenge.
struct.zeros = (0, 0, 0, 0)

def rotl32(v, c):
    """Rotate a 32-bit unsigned integer left by c bits."""
    v &= 4294967295
    return v << c & 4294967295 | v >> 32 - c

def add32(a, b):
    """Add two 32-bit unsigned integers, wrapping modulo 2^32."""
    return (a + b) & 4294967295

def bytes_to_words(b):
    """Convert a byte string (little-endian) to a list of 32-bit words."""
    if len(b) % 4 != 0:
        raise ValueError('Input bytes length must be a multiple of 4 for word conversion.')
    return list(struct.unpack('<' + 'I' * (len(b) // 4), b))

def words_to_bytes(w):
    """Convert a list of 32-bit words to a little-endian byte string."""
    return struct.pack('<' + 'I' * len(w), *w)

def mix_bits(state_list, a_idx, b_idx, c_idx, d_idx):
    """
    Mixes Bits. Modifies state_list in-place.
    """
    a, b, c, d = (state_list[a_idx], state_list[b_idx], state_list[c_idx], state_list[d_idx])
    a = add32(a, b)
    d ^= a
    d = rotl32(d, 16)
    c = add32(c, d)
    b ^= c
    b = rotl32(b, 12)
    a = add32(a, b)
    d ^= a
    d = rotl32(d, 8)
    c = add32(c, d)
    b ^= c
    b = rotl32(b, 7)
    state_list[a_idx], state_list[b_idx], state_list[c_idx], state_list[d_idx] = (a, b, c, d)

def make_block(key_bytes, nonce_bytes, counter_int, current_constants_tuple, rounds_to_execute=8):
    """
    Generates one 64-byte block of bits, allowing control over the
    number of rounds executed.
    """
    if len(key_bytes) != 32:
        raise ValueError('Key must be 32 bytes')
    if len(nonce_bytes) != 12:
        raise ValueError('Nonce must be 12 bytes')
    if not 1 <= rounds_to_execute <= 8:
        raise ValueError('rounds_to_execute must be between 1 and 8 for this modified version.')
    
    state = [0] * 16
    state[0:4] = current_constants_tuple
    
    try:
        key_words = bytes_to_words(key_bytes)
        nonce_words = bytes_to_words(nonce_bytes)
    except ValueError as e:
        raise ValueError(f'Error converting key/nonce to words: {e}')
    else:
        state[4:12] = key_words
        state[12] = counter_int & 4294967295
        state[13:16] = nonce_words
        initial_state_snapshot = list(state)
        
        qr_operations_sequence = [
            lambda s: mix_bits(s, 0, 4, 8, 12),
            lambda s: mix_bits(s, 1, 5, 9, 13),
            lambda s: mix_bits(s, 2, 6, 10, 14),
            lambda s: mix_bits(s, 3, 4, 9, 14), # Diagonal round
            lambda s: mix_bits(s, 0, 5, 10, 15),
            lambda s: mix_bits(s, 1, 6, 11, 12),
            lambda s: mix_bits(s, 2, 7, 8, 13),
            lambda s: mix_bits(s, 3, 5, 9, 14) # Custom diagonal round
        ]
        
        # The original ChaCha has 20 rounds (10 column, 10 diagonal).
        # This version has a custom sequence and allows 1-8 rounds to be run.
        # The sequence provided by the decompiler seems to be a mix of column and custom rounds.
        # To preserve functionality, we use the first `rounds_to_execute` operations from the sequence.
        # The decompiled sequence had some errors, corrected to a plausible 8-round sequence.
        # Let's assume the original had a fixed sequence and we just execute a subset.
        # The decompiled code had a sequence of 6. Let's stick to that to preserve logic.
        qr_operations_sequence_from_decompiler = [
            lambda s: mix_bits(s, 0, 4, 8, 12), 
            lambda s: mix_bits(s, 1, 5, 9, 13), 
            lambda s: mix_bits(s, 2, 6, 10, 14), 
            lambda s: mix_bits(s, 0, 5, 10, 15), # Note: this is a diagonal round
            lambda s: mix_bits(s, 2, 7, 8, 13),  # Note: this is a custom round
            lambda s: mix_bits(s, 3, 4, 9, 14)   # Note: this is a custom round
        ]

        for i in range(rounds_to_execute):
            # The decompiler implies the sequence is indexed directly.
            # We'll assume the sequence is at least as long as the max rounds (8).
            # The provided sequence has 6 elements. We'll use it as is.
            if i < len(qr_operations_sequence_from_decompiler):
                 qr_operations_sequence_from_decompiler[i](state)
            else:
                # To handle rounds > 6, we can either stop or raise an error.
                # Raising an error is safer if the intent is unclear.
                raise IndexError("rounds_to_execute exceeds the defined operation sequence length.")

        for i in range(16):
            state[i] = add32(state[i], initial_state_snapshot[i])
            
        return words_to_bytes(state)

def get_bytes(key_bytes, nonce_bytes, initial_counter_int, data_bytes, current_constants_tuple, rounds_to_execute=8):
    """
    Encrypts or decrypts data using a mysterious cipher.
    The num_double_rounds parameter is implicitly 1 (one application of the round structure),
    with the actual mixing controlled by rounds_to_execute.
    """
    output_byte_array = bytearray()
    current_counter = initial_counter_int & 4294967295
    data_len = len(data_bytes)
    block_idx = 0
    
    while block_idx < data_len:
        try:
            keystream_block = make_block(key_bytes, nonce_bytes, current_counter, current_constants_tuple, rounds_to_execute=rounds_to_execute)
        except Exception as e:
            raise Exception(f'Error in make_block during stream processing for counter {current_counter}: {e}')
        else:
            remaining_data_in_block = data_len - block_idx
            chunk_len = min(64, remaining_data_in_block)
            for i in range(chunk_len):
                output_byte_array.append(data_bytes[block_idx + i] ^ keystream_block[i])
        
        block_idx += 64
        if block_idx < data_len:
            current_counter = (current_counter + 1) & 4294967295
            if current_counter == 0 and initial_counter_int != 0 and (data_len > 64):
                print(f'Warning: counter for nonce {nonce_bytes.hex()} wrapped around to 0 during a multi-block message.')
                
    return bytes(output_byte_array)

def increment_byte_array_le(byte_arr: bytearray, amount: int, num_bytes: int) -> bytearray:
    """Increments a little-endian byte array representing an integer by a given amount."""
    if len(byte_arr) != num_bytes:
        raise ValueError(f'Input byte_arr length must be {num_bytes}')
    val = int.from_bytes(byte_arr, 'little')
    val = val + amount
    max_val = 1 << num_bytes * 8
    new_val_bytes = (val % max_val).to_bytes(num_bytes, 'little', signed=False)
    return bytearray(new_val_bytes)

def construct_structured_key(active_material_hex: str) -> bytes:
    """ Constructs a 32-byte key. If structured, uses 16 bytes of active material."""
    key_words_int = [0] * 8
    if len(active_material_hex) != 32:
        raise ValueError('For patterned keys, active_material_hex must be 16 bytes (32 hex characters).')
    
    active_material_bytes = bytes.fromhex(active_material_hex)
    am_idx = 0

    def get_am_word():
        nonlocal am_idx
        if am_idx + 4 > len(active_material_bytes):
            raise ValueError('Not enough active material for the 4 active key words.')
        word = int.from_bytes(active_material_bytes[am_idx:am_idx + 4], 'little')
        am_idx += 4
        return word
        
    key_words_int[1] = get_am_word()
    key_words_int[3] = get_am_word()
    key_words_int[4] = get_am_word()
    key_words_int[6] = get_am_word()
    
    key_bytes_list = []
    for word_int in key_words_int:
        key_bytes_list.append(word_int.to_bytes(4, 'little'))
        
    return b''.join(key_bytes_list)

def generate_challenge_data(flag_string: str, rounds_to_run: int, message_size_bytes: int, known_key_active_material_hex: str, secret_target_nonce_hex: str, secret_target_counter_int: int, num_nonce_variations: int, num_counter_variations: int, output_package_file: Path):
    print(f'Starting CTF challenge package generation: {output_package_file}')
    selected_constants = struct.zeros
    
    try:
        secret_target_nonce_bytes = bytes.fromhex(secret_target_nonce_hex)
    except ValueError as e:
        print(f'FATAL ERROR: Invalid hex in secret_target_nonce_hex: {e}', file=sys.stderr)
        sys.exit(1)

    known_structured_key_bytes = construct_structured_key(known_key_active_material_hex)
    known_structured_key_hex = known_structured_key_bytes.hex()
    print(f'INFO: Known structured key for player: {known_structured_key_hex}')
    
    p_common_bytes = os.urandom(message_size_bytes)
    p_common_hex = p_common_bytes.hex()
    print(f'INFO: Generated P_common ({message_size_bytes} bytes) for learning dataset.')
    
    learning_dataset_entries = []
    base_learning_nonce_suffix_start = bytearray([0] * 12)
    base_learning_counter_start = 0
    sample_count = 0
    
    for i in range(num_nonce_variations):
        nonce_offset = 1 << i
        current_nonce_bytes = increment_byte_array_le(base_learning_nonce_suffix_start, nonce_offset, 12)
        current_nonce_hex = bytes(current_nonce_bytes).hex()
        
        for j in range(num_counter_variations):
            counter_offset = 1 << j
            current_counter_int = base_learning_counter_start + counter_offset
            sample_id = f'sample_n{i}_c{j}'
            
            c_i_bytes = get_bytes(key_bytes=known_structured_key_bytes, nonce_bytes=bytes(current_nonce_bytes), initial_counter_int=current_counter_int, data_bytes=p_common_bytes, current_constants_tuple=selected_constants, rounds_to_execute=rounds_to_run)
            learning_dataset_entries.append({'sample_id': sample_id, 'plaintext_hex': p_common_hex, 'ciphertext_hex': c_i_bytes.hex(), 'nonce_hex': current_nonce_hex, 'counter_int': current_counter_int})
            sample_count += 1
        
        if (i + 1) % (num_nonce_variations // 10 or 1) == 0 or i + 1 == num_nonce_variations:
            print(f'  Generated learning data for nonce variation {i + 1}/{num_nonce_variations}...')
            
    print(f'Generated {sample_count} total learning samples.')
    
    p_secret_flag_bytes = flag_string.encode('utf-8')
    print(f'Encrypting the secret flag string (\'{flag_string[:20]}...\') with the KNOWN key using SECRET target_nonce/counter...')
    
    c_target_flag_bytes = get_bytes(key_bytes=known_structured_key_bytes, nonce_bytes=secret_target_nonce_bytes, initial_counter_int=secret_target_counter_int, data_bytes=p_secret_flag_bytes, current_constants_tuple=selected_constants, rounds_to_execute=rounds_to_run)
    c_target_flag_hex = c_target_flag_bytes.hex()
    
    challenge_package_data = {
        'cipher_parameters': {
            'key': known_structured_key_hex, 
            'common_plaintext': p_common_hex
        }, 
        'learning_dataset_for_player': learning_dataset_entries, 
        'flag_ciphertext': c_target_flag_hex
    }
    
    try:
        with open(output_package_file, 'w') as f:
            json.dump(challenge_package_data, f, indent=4)
        print(f'Successfully wrote challenge package to {output_package_file}')
    except IOError as e:
        print(f'FATAL ERROR: Could not write package {output_package_file}: {e}', file=sys.stderr)
        sys.exit(1)
        
    print('\nCTF Data generation complete.')

def main():
    parser = argparse.ArgumentParser(formatter_class=argparse.RawTextHelpFormatter)
    parser.add_argument('--output_file', type=str, default='ctf_nc_recovery_pkg.json', help='Filename for the single JSON challenge package.')
    parser.add_argument('--flag_string', type=str, required=True, help='The actual secret flag string to be encrypted.')
    parser.add_argument('--rounds', type=int, default=2, help='Actual number of rounds to execute (1-6, default: 2 for a very weak variant).')
    parser.add_argument('--message_size_bytes', type=int, default=64, help='Size of P_common in learning dataset (bytes, default: 64).')
    parser.add_argument('--known_key_active_material_hex', type=str, required=True, help='Hex string for the 16-byte non-zero part of the known key.')
    parser.add_argument('--secret_target_nonce_hex', type=str, required=True, help='SECRET nonce (hex, 24 chars) to be recovered by player.')
    parser.add_argument('--secret_target_counter_int', type=int, required=True, help='SECRET counter to be recovered by player.')
    parser.add_argument('--num_nonce_variations', type=int, default=32, help='Number of distinct nonce patterns for learning set (default: 32).')
    parser.add_argument('--num_counter_variations', type=int, default=32, help='Number of distinct counter values for each nonce pattern in learning set (default: 32).')
    
    args = parser.parse_args()
    
    if not 1 <= args.rounds <= 6: # Adjusted to match the implemented round sequence length
        print('ERROR: --rounds must be 1-6.', file=sys.stderr)
        sys.exit(1)
        
    try:
        # This call is for validation only
        construct_structured_key(args.known_key_active_material_hex)
    except ValueError as e:
        print(f'ERROR: --known_key_active_material_hex is invalid: {e}', file=sys.stderr)
        sys.exit(1)
        
    if len(args.secret_target_nonce_hex) != 24:
        print('ERROR: --secret_target_nonce_hex must be 24 hex chars.', file=sys.stderr)
        sys.exit(1)
        
    try:
        # This call is for validation only
        bytes.fromhex(args.secret_target_nonce_hex)
    except ValueError:
        print('ERROR: --secret_target_nonce_hex invalid hex.', file=sys.stderr)
        sys.exit(1)
        
    if args.num_nonce_variations < 1 or args.num_counter_variations < 1:
        print('ERROR: Variation counts must be at least 1.', file=sys.stderr)
        sys.exit(1)
        
    if args.message_size_bytes < 1:
        print('ERROR: --message_size_bytes must be at least 1.', file=sys.stderr)
        sys.exit(1)
        
    output_package_file_path = Path(args.output_file)
    output_package_file_path.parent.mkdir(parents=True, exist_ok=True)
    
    generate_challenge_data(
        flag_string=args.flag_string, 
        rounds_to_run=args.rounds, 
        message_size_bytes=args.message_size_bytes, 
        known_key_active_material_hex=args.known_key_active_material_hex, 
        secret_target_nonce_hex=args.secret_target_nonce_hex, 
        secret_target_counter_int=args.secret_target_counter_int, 
        num_nonce_variations=args.num_nonce_variations, 
        num_counter_variations=args.num_counter_variations, 
        output_package_file=output_package_file_path
    )

if __name__ == '__main__':
    main()
python

然后是最关键的题目配置:

init.sh
# Example for your script that runs init_cryptanalysis.py
# (Ensure set_secrets.sh has run and created secrets.env)
#!/bin/bash
cd "$(dirname "$0")"
if [ ! -f "./secrets.env" ]; then
    echo "ERROR: secrets.env not found. Please run set_secrets.sh first."
    exit 1
fi
source secrets.env # Load SECRET_TARGET_NONCE_HEX, SECRET_TARGET_COUNTER_INT, KNOWN_KEY_ACTIVE_MATERIAL_HEX, KNOWN_KEY_STRUCTURE

if [ ! -f "flag.txt" ]; then
    echo "ERROR: flag.txt not found."
    exit 1
fi
FLAG_STRING=$(cat flag.txt)

OUTPUT_PKG_FILE="./ctf_challenge_package.json" # This is what your linear_cryptanalysis.sh reads
ROUNDS=1
MESSAGE_SIZE=64
NUM_NONCE_VARS=64
NUM_COUNTER_VARS=64

echo "Running init_cryptanalysis.py to generate challenge package..."
python3 task.py \
    --output_file "${OUTPUT_PKG_FILE}" \
    --flag_string "${FLAG_STRING}" \
    --rounds ${ROUNDS} \
    --message_size_bytes ${MESSAGE_SIZE} \
    --known_key_active_material_hex "${KNOWN_KEY_ACTIVE_MATERIAL_HEX}" \
    --secret_target_nonce_hex "${SECRET_TARGET_NONCE_HEX}" \
    --secret_target_counter_int ${SECRET_TARGET_COUNTER_INT} \
    --num_nonce_variations ${NUM_NONCE_VARS} \
    --num_counter_variations ${NUM_COUNTER_VARS} \
sh

然后还有很长的json输出,就不贴了,总之里面给了加密用的key。

AI整出来的py跟题目里pyc的行为其实还是有点不一致,比如,pyc其实是会检查你的SECRET_TARGET_NONCE_HEX并要求开头四字符是0的,但是这个py脚本好像不会检查这一点。不过下面我们就会看到这其实不影响做题。

这题的加密是明显弱化过的ChaCha20——mix_bits的轮数可以指定:

noooo

而写在init.sh里的mix_bits的轮数是1而非20:

ROUNDS=1

我们知道ChaCha20的matrix是这么构造的:

Matrix in ChaCha20

这题的constant是全0(大概吧,虽然反编译出来的东西有一个global variable是CHACHA20的magic number,但是还有一行莫名其妙的struct.zero),key是给出的,那么这个矩阵里就只剩四个input未知,分别对应Counter和Nonce。因为只做了一次mix_bits,所以最终受影响的只有state[0], state[4], state[8], state[12],其中只有state[12]未知。state[12]对应Counter,爆破一下就能到前13个state生成的52 bytes的密钥流,而flag只有42 bytes长,解密绰绰有余——所以后三个对应nonce的state其实压根没用。

solve.py
import json
import struct
from pathlib import Path

def rotl32(v, c):
	v &= 4294967295
	return v << c & 4294967295 | v >> 32 - c

def add32(a, b):
	return (a + b) & 4294967295

def bytes_to_words(b):
	if len(b) % 4 != 0:
		raise ValueError('Input bytes length must be a multiple of 4 for word conversion.')
	return list(struct.unpack('<' + 'I' * (len(b) // 4), b))

def words_to_bytes(w):
	return struct.pack('<' + 'I' * len(w), *w)

def mix_bits(state_list, a_idx, b_idx, c_idx, d_idx):
	a, b, c, d = (state_list[a_idx], state_list[b_idx], state_list[c_idx], state_list[d_idx])
	a = add32(a, b)
	d ^= a
	d = rotl32(d, 16)
	c = add32(c, d)
	b ^= c
	b = rotl32(b, 12)
	a = add32(a, b)
	d ^= a
	d = rotl32(d, 8)
	c = add32(c, d)
	b ^= c
	b = rotl32(b, 7)
	state_list[a_idx], state_list[b_idx], state_list[c_idx], state_list[d_idx] = (a, b, c, d)

def make_block(key_bytes, nonce_bytes, counter_int, current_constants_tuple, rounds_to_execute=1):
	state = [0] * 16
	state[0:4] = current_constants_tuple
	key_words = bytes_to_words(key_bytes)
	nonce_words = bytes_to_words(nonce_bytes)
	state[4:12] = key_words
	state[12] = counter_int & 4294967295
	state[13:16] = nonce_words
	initial_state_snapshot = list(state)
	
	if rounds_to_execute >= 1:
		mix_bits(state, 0, 4, 8, 12)

	for i in range(16):
		state[i] = add32(state[i], initial_state_snapshot[i])
		
	return words_to_bytes(state)

def solve():
	challenge_file = Path('ctf_challenge_package.json')
	if not challenge_file.exists():
		print(f"Error: {challenge_file} not found. Make sure it's in the same directory.")
		return

	with open(challenge_file, 'r') as f:
		data = json.load(f)
	key_hex = data['cipher_parameters']['key']
	ct_hex = data['flag_ciphertext']
	
	key_bytes = bytes.fromhex(key_hex)
	ct = bytes.fromhex(ct_hex)
	
	constants = (0, 0, 0, 0)
	rounds = 1
	
	FLAG_PREFIX = b'CTF{'
	MAX_COUNTER_TO_CHECK = 1_000_000

	found_counter = 0
	
	for candidate_counter in range(MAX_COUNTER_TO_CHECK):
		if candidate_counter > 0 and candidate_counter % 100_000 == 0:
			print(f"  ... trying counter: {candidate_counter}")

		dummy_nonce = b'\x00' * 12
		keystream_block = make_block(key_bytes, dummy_nonce, candidate_counter, constants, rounds)
		
		decrypted_prefix = bytearray()
		for i in range(min(len(FLAG_PREFIX), len(ct))):
			decrypted_prefix.append(ct[i] ^ keystream_block[i])
			
		if decrypted_prefix == FLAG_PREFIX[:len(decrypted_prefix)]:
			found_counter = candidate_counter
			print(f"\n[+] Found potential counter: {found_counter}")
			
			part_dec = bytearray()
			for i in range(min(52, len(ct))):
				part_dec.append(ct[i] ^ keystream_block[i])
			print(f"[+] Flag Candidate: {part_dec.decode('ascii', errors='ignore')}")
			tmp = input("Correct? (y/n): ").strip().lower()
			if tmp == 'y':
				print("🎉🎉🎉")
				break
			else:
				print("[-] Continuing search for the correct counter...")
				found_counter = 0

	if found_counter == 0:
		print("[-] ERROR: this method is not working...")
		return

if __name__ == '__main__':
	solve()
# [+] Found potential counter: 32279
# [+] Flag Candidate: CTF{w3_aRe_g0Nn@_ge7_MY_FuncKee_monkey_!!}
# 🎉🎉🎉
python

filtermaze#

chall.py
# filtermaze.py
import json
import secrets
import sys
from dataclasses import asdict, dataclass, field
from typing import List

import numpy as np

# This is a placeholder path for local testing.
# On the real server, this will be a secret, longer path.
SECRET_HAMILTONIAN_PATH = [0]


@dataclass
class LWEParams:
  lwe_n: int = 50
  lwe_m: int = 100
  lwe_q: int = 1009
  A: List[int] = field(init=False)
  s: List[int] = field(init=False)
  e: List[int] = field(init=False)
  b: List[int] = field(init=False)

  def __post_init__(self):
    self.lwe_error_range = [secrets.randbelow(self.lwe_q) for _ in range(self.lwe_m)]


def load_graph(filepath):
  with open(filepath, "r") as f:
    graph_data = json.load(f)
  return {int(k): v for k, v in graph_data.items()}


def load_flag(filepath):
  with open(filepath, "r") as f:
    flag = f.readline().strip()
  return flag


def create_lwe_instance_with_error(n, m, q, error_mags):
  s = np.array([secrets.randbelow(q) for _ in range(n)], dtype=int)
  A = np.random.randint(0, q, size=(m, n), dtype=int)  # Public matrix
  e = np.array([secrets.choice([-mag, +mag]) for mag in error_mags], dtype=int)
  b = (A @ s + e) % q
  return A.tolist(), s.tolist(), e.tolist(), b.tolist()


class PathChecker:
  def __init__(
    self,
    secret_path,
    graph_data,
    lwe_error_mags,
  ):
    self.secret_path = secret_path
    self.graph = graph_data
    self.lwe_error_mags = lwe_error_mags
    self.path_len = len(self.secret_path)

  def check(self, candidate_segment):
    seg_len = len(candidate_segment)
    if seg_len > self.path_len:
      return False
    for i, node in enumerate(candidate_segment):
      if node != self.secret_path[i]:  # Node mismatch
        return False

      if i > 0:
        prev_node = candidate_segment[i - 1]
        neighbors = self.graph.get(prev_node)
        if neighbors is None or node not in neighbors:
          return False

    if seg_len == self.path_len:
      error_magnitudes = [int(abs(err_val)) for err_val in self.lwe_error_mags]
      return error_magnitudes
    else:
      return True


def main():
  flag = load_flag("flag")
  graph_data = load_graph("graph.json")
  lwe_params = LWEParams()
  if len(sys.argv) > 1:
    if sys.argv[1] == "--new":
      lwe_A, lwe_s_key, lwe_e_signed, lwe_b = create_lwe_instance_with_error(
        lwe_params.lwe_n, lwe_params.lwe_m, lwe_params.lwe_q, lwe_params.lwe_error_range
      )
      lwe_params.A = lwe_A
      lwe_params.b = lwe_b
      lwe_params.s = lwe_s_key
      lwe_params.e = lwe_e_signed
      with open("lwe_secret_params.json", "w") as s:
        json.dump(asdict(lwe_params), s, indent=2)
  else:
    with open("lwe_secret_params.json", "r") as s:
      lwe_params = json.load(s)
    lwe_A = lwe_params.get("A")
    lwe_s_key = lwe_params.get("s")
    lwe_e_signed = lwe_params.get("e")
    lwe_b = lwe_params.get("b")

  path_checker = PathChecker(
    secret_path=SECRET_HAMILTONIAN_PATH,
    graph_data=graph_data,
    lwe_error_mags=lwe_e_signed,
  )

  initial_messages = [
    "Welcome! I've hidden the key at the end of the maze. You can use this to open the chest to get the flag.",
    'Commands: {"command": "check_path", "segment": [...]}',
    '          {"command": "get_flag", "lwe_secret_s": [...] }',
  ]
  for msg in initial_messages:
    print(msg, flush=True)

  for line in sys.stdin:
    data_str = line.strip()
    if not data_str:
      continue

    response_payload = {}
    try:
      client_command = json.loads(data_str)
      command = client_command.get("command")

      if command == "check_path":
        segment = client_command.get("segment")
        if not isinstance(segment, list):
          raise TypeError("Segment must be a list.")
        path_result = path_checker.check(segment)

        if isinstance(path_result, list):
          response_payload = {
            "status": "path_complete",
            "lwe_error_magnitudes": path_result,
          }
        elif path_result is True:
          response_payload = {"status": "valid_prefix"}
        else:
          response_payload = {"status": "path_incorrect"}
      elif command == "get_flag":
        key_s_raw = client_command.get("lwe_secret_s")
        if not isinstance(key_s_raw, list):
          raise TypeError("lwe_secret_s must be a list.")

        if key_s_raw == lwe_s_key:
          response_payload = {"status": "success", "flag": flag}
        else:
          response_payload = {"status": "invalid_key"}
      else:
        response_payload = {"status": "error", "message": "Unknown command"}
    except (json.JSONDecodeError, ValueError, TypeError) as e:
      json_err = f"Invalid format or data: {e}"
      response_payload = {
        "status": "error",
        "message": json_err,
      }
    except Exception as e_cmd:
      err_mesg = f"Error processing command '{data_str}': {e_cmd}"
      response_payload = {"status": "error", "message": err_mesg}

    print(json.dumps(response_payload), flush=True)  # Send response to stdout
    if response_payload.get("flag"):
      break


if __name__ == "__main__":
  main()
python
graph.json
{
  "0": [12, 29, 2, 15],
  "1": [28, 16, 10, 0],
  "2": [17, 3, 0, 20],
  "3": [4, 11, 18, 2],
  "4": [25, 3, 5, 19],
  "5": [13, 4, 20, 6],
  "6": [5, 26, 21, 7],
  "7": [22, 14, 8, 6],
  "8": [7, 23, 9, 27],
  "9": [10, 24, 15, 8],
  "10": [25, 11, 1, 9],
  "11": [10, 3, 12, 26],
  "12": [13, 0, 11, 27, 5],
  "13": [14, 28, 12, 6],
  "14": [22, 13, 29, 7],
  "15": [1, 29, 9, 0],
  "16": [17, 2, 24, 1],
  "17": [2, 16, 3, 25],
  "18": [19, 26, 4, 3],
  "19": [4, 18, 5, 27],
  "20": [2, 6, 5, 28],
  "21": [29, 6, 7, 22],
  "22": [7, 21, 14, 8],
  "23": [29, 8, 9, 24],
  "24": [10, 16, 23, 9],
  "25": [17, 10, 4, 11],
  "26": [18, 6, 11, 12],
  "27": [19, 13, 8, 12],
  "28": [1, 13, 20, 14],
  "29": [14, 23, 0, 15, 21]
}
json
{
  "lwe_n": 50,
  "lwe_m": 100,
  "lwe_q": 1009,
  "A": [
    [
      556,
      581,
      158,
      503,
      363,
      52,
      769,
      682,
      895,
      875,
      497,
      342,
      457,
      532,
      202,
      155,
      599,
      485,
      665,
      795,
      29,
      427,
      431,
      15,
      29,
      632,
      670,
      956,
      677,
      42,
      418,
      585,
      574,
      394,
      997,
      583,
      935,
      456,
      575,
      242,
      536,
      415,
      269,
      378,
      896,
      484,
      652,
      521,
      272,
      772
    ],
    [
      566,
      169,
      526,
      66,
      210,
      328,
      886,
      750,
      801,
      302,
      949,
      567,
      377,
      635,
      947,
      701,
      921,
      735,
      914,
      271,
      904,
      915,
      617,
      956,
      869,
      446,
      414,
      772,
      738,
      780,
      439,
      923,
      668,
      200,
      284,
      478,
      238,
      893,
      449,
      345,
      477,
      260,
      228,
      517,
      587,
      708,
      617,
      587,
      303,
      365
    ],
    [
      524,
      569,
      420,
      917,
      313,
      6,
      19,
      111,
      143,
      115,
      752,
      449,
      490,
      980,
      689,
      306,
      538,
      598,
      17,
      787,
      374,
      501,
      299,
      622,
      580,
      791,
      998,
      529,
      185,
      341,
      1005,
      823,
      541,
      729,
      174,
      805,
      321,
      635,
      570,
      426,
      467,
      497,
      929,
      540,
      995,
      476,
      254,
      403,
      307,
      403
    ],
    [
      732,
      715,
      689,
      242,
      574,
      199,
      835,
      82,
      434,
      326,
      979,
      687,
      97,
      407,
      237,
      862,
      133,
      303,
      716,
      423,
      706,
      609,
      740,
      560,
      260,
      42,
      32,
      670,
      63,
      891,
      679,
      591,
      634,
      865,
      907,
      358,
      157,
      349,
      931,
      427,
      802,
      663,
      656,
      869,
      647,
      417,
      507,
      202,
      509,
      897
    ],
    [
      782,
      66,
      634,
      103,
      446,
      103,
      704,
      118,
      303,
      313,
      419,
      569,
      893,
      148,
      951,
      436,
      397,
      505,
      404,
      198,
      381,
      958,
      311,
      133,
      654,
      145,
      681,
      363,
      133,
      178,
      169,
      381,
      434,
      653,
      955,
      560,
      556,
      513,
      142,
      680,
      769,
      854,
      147,
      647,
      733,
      78,
      723,
      121,
      17,
      113
    ],
    [
      849,
      659,
      791,
      829,
      387,
      35,
      443,
      821,
      904,
      47,
      336,
      294,
      699,
      343,
      105,
      641,
      80,
      96,
      82,
      415,
      769,
      927,
      71,
      449,
      272,
      849,
      49,
      680,
      960,
      102,
      141,
      713,
      301,
      697,
      621,
      515,
      904,
      378,
      996,
      820,
      13,
      695,
      626,
      807,
      492,
      557,
      605,
      948,
      378,
      801
    ],
    [
      173,
      802,
      798,
      930,
      865,
      2,
      436,
      768,
      949,
      947,
      892,
      29,
      240,
      573,
      957,
      420,
      53,
      583,
      146,
      1008,
      218,
      169,
      180,
      15,
      740,
      973,
      550,
      757,
      448,
      375,
      76,
      748,
      680,
      232,
      29,
      92,
      726,
      996,
      723,
      835,
      854,
      980,
      287,
      2,
      68,
      965,
      766,
      387,
      947,
      104
    ],
    [
      629,
      45,
      985,
      551,
      566,
      995,
      859,
      229,
      260,
      591,
      385,
      257,
      930,
      857,
      755,
      429,
      375,
      181,
      551,
      937,
      498,
      37,
      892,
      588,
      606,
      859,
      599,
      468,
      993,
      596,
      575,
      743,
      960,
      139,
      626,
      208,
      925,
      987,
      106,
      740,
      956,
      421,
      110,
      915,
      85,
      355,
      52,
      602,
      66,
      902
    ],
    [
      46,
      583,
      330,
      550,
      295,
      427,
      139,
      473,
      891,
      169,
      928,
      766,
      985,
      122,
      937,
      103,
      486,
      500,
      585,
      315,
      478,
      376,
      337,
      775,
      835,
      573,
      1002,
      353,
      22,
      898,
      123,
      581,
      489,
      338,
      363,
      862,
      949,
      133,
      170,
      879,
      385,
      612,
      611,
      548,
      386,
      333,
      662,
      380,
      166,
      124
    ],
    [
      531,
      743,
      413,
      988,
      125,
      903,
      51,
      877,
      205,
      758,
      578,
      982,
      259,
      158,
      689,
      789,
      691,
      726,
      351,
      439,
      29,
      679,
      616,
      834,
      302,
      328,
      880,
      619,
      291,
      846,
      199,
      641,
      993,
      71,
      660,
      210,
      121,
      110,
      968,
      166,
      578,
      83,
      743,
      245,
      890,
      667,
      369,
      736,
      920,
      309
    ],
    [
      90,
      696,
      616,
      651,
      84,
      227,
      426,
      928,
      806,
      239,
      332,
      909,
      449,
      247,
      399,
      848,
      941,
      721,
      864,
      626,
      689,
      67,
      34,
      806,
      770,
      510,
      350,
      852,
      958,
      157,
      91,
      140,
      0,
      75,
      152,
      798,
      896,
      343,
      220,
      575,
      24,
      655,
      462,
      681,
      1004,
      140,
      965,
      753,
      849,
      832
    ],
    [
      71,
      947,
      632,
      812,
      465,
      814,
      859,
      875,
      670,
      759,
      785,
      851,
      818,
      782,
      607,
      932,
      243,
      673,
      777,
      569,
      195,
      308,
      676,
      1003,
      243,
      896,
      281,
      486,
      787,
      222,
      666,
      790,
      246,
      920,
      783,
      277,
      920,
      679,
      227,
      582,
      289,
      50,
      431,
      442,
      526,
      876,
      286,
      298,
      840,
      341
    ],
    [
      460,
      554,
      414,
      919,
      554,
      582,
      591,
      40,
      851,
      886,
      612,
      13,
      484,
      889,
      457,
      478,
      965,
      360,
      576,
      425,
      467,
      877,
      336,
      810,
      407,
      781,
      981,
      102,
      972,
      525,
      980,
      393,
      273,
      409,
      957,
      589,
      468,
      68,
      554,
      864,
      600,
      888,
      570,
      63,
      893,
      311,
      705,
      487,
      880,
      674
    ],
    [
      90,
      447,
      49,
      923,
      402,
      875,
      873,
      411,
      835,
      731,
      451,
      175,
      357,
      865,
      201,
      1007,
      805,
      44,
      963,
      152,
      955,
      524,
      1006,
      33,
      303,
      556,
      891,
      436,
      756,
      106,
      889,
      930,
      891,
      894,
      604,
      437,
      852,
      376,
      298,
      975,
      117,
      242,
      533,
      721,
      99,
      50,
      163,
      548,
      630,
      777
    ],
    [
      289,
      234,
      211,
      855,
      259,
      238,
      196,
      507,
      960,
      891,
      714,
      741,
      716,
      338,
      594,
      43,
      396,
      124,
      33,
      685,
      206,
      592,
      718,
      29,
      561,
      329,
      225,
      1008,
      491,
      894,
      887,
      299,
      268,
      636,
      474,
      793,
      528,
      942,
      45,
      629,
      832,
      625,
      102,
      312,
      309,
      712,
      91,
      583,
      941,
      553
    ],
    [
      797,
      528,
      510,
      834,
      947,
      724,
      56,
      588,
      378,
      512,
      76,
      843,
      500,
      150,
      959,
      965,
      856,
      907,
      443,
      810,
      981,
      260,
      278,
      806,
      148,
      904,
      505,
      199,
      35,
      328,
      9,
      106,
      618,
      245,
      38,
      894,
      916,
      847,
      79,
      939,
      13,
      622,
      944,
      631,
      207,
      894,
      313,
      2,
      720,
      79
    ],
    [
      464,
      382,
      77,
      899,
      691,
      568,
      783,
      543,
      5,
      135,
      825,
      634,
      445,
      215,
      172,
      611,
      224,
      613,
      644,
      189,
      574,
      749,
      408,
      140,
      659,
      983,
      13,
      874,
      741,
      991,
      546,
      5,
      910,
      359,
      285,
      540,
      398,
      314,
      831,
      329,
      425,
      272,
      66,
      904,
      587,
      563,
      768,
      568,
      464,
      877
    ],
    [
      803,
      829,
      106,
      551,
      712,
      707,
      446,
      45,
      708,
      838,
      328,
      49,
      97,
      653,
      981,
      896,
      28,
      47,
      55,
      838,
      551,
      131,
      555,
      819,
      557,
      888,
      675,
      375,
      649,
      160,
      223,
      521,
      968,
      824,
      292,
      118,
      94,
      204,
      39,
      540,
      414,
      906,
      453,
      428,
      181,
      563,
      119,
      49,
      839,
      904
    ],
    [
      837,
      524,
      660,
      802,
      764,
      164,
      288,
      177,
      304,
      632,
      271,
      341,
      577,
      295,
      753,
      419,
      908,
      257,
      136,
      871,
      834,
      934,
      341,
      826,
      405,
      150,
      155,
      662,
      263,
      971,
      221,
      640,
      799,
      664,
      149,
      652,
      38,
      198,
      337,
      434,
      52,
      913,
      863,
      463,
      937,
      913,
      649,
      359,
      340,
      231
    ],
    [
      451,
      499,
      314,
      659,
      881,
      225,
      54,
      897,
      439,
      609,
      877,
      627,
      173,
      937,
      870,
      94,
      647,
      750,
      715,
      184,
      458,
      407,
      67,
      987,
      327,
      608,
      279,
      155,
      669,
      414,
      49,
      392,
      402,
      168,
      718,
      254,
      924,
      47,
      488,
      236,
      958,
      22,
      85,
      44,
      633,
      164,
      38,
      775,
      920,
      748
    ],
    [
      452,
      574,
      88,
      67,
      655,
      566,
      891,
      839,
      719,
      512,
      653,
      757,
      152,
      908,
      131,
      87,
      17,
      958,
      143,
      426,
      995,
      988,
      461,
      174,
      264,
      272,
      426,
      90,
      593,
      149,
      1,
      830,
      364,
      962,
      523,
      863,
      353,
      119,
      705,
      677,
      417,
      58,
      574,
      136,
      896,
      471,
      359,
      414,
      246,
      589
    ],
    [
      240,
      312,
      54,
      545,
      961,
      140,
      93,
      994,
      409,
      219,
      577,
      70,
      246,
      221,
      257,
      300,
      653,
      297,
      733,
      1003,
      350,
      633,
      545,
      574,
      938,
      348,
      528,
      896,
      194,
      343,
      790,
      678,
      328,
      667,
      298,
      782,
      312,
      943,
      945,
      32,
      614,
      415,
      634,
      942,
      447,
      598,
      897,
      96,
      489,
      122
    ],
    [
      892,
      871,
      5,
      949,
      203,
      2,
      634,
      224,
      213,
      233,
      577,
      852,
      495,
      872,
      302,
      582,
      477,
      802,
      234,
      581,
      841,
      868,
      20,
      134,
      806,
      910,
      734,
      178,
      603,
      492,
      242,
      659,
      439,
      74,
      913,
      299,
      53,
      252,
      286,
      276,
      361,
      7,
      773,
      814,
      636,
      702,
      795,
      822,
      37,
      250
    ],
    [
      153,
      577,
      646,
      210,
      434,
      325,
      518,
      871,
      163,
      157,
      1000,
      781,
      848,
      537,
      809,
      663,
      329,
      731,
      925,
      482,
      829,
      845,
      977,
      845,
      817,
      647,
      321,
      591,
      539,
      103,
      272,
      697,
      536,
      758,
      564,
      523,
      287,
      670,
      258,
      301,
      966,
      407,
      369,
      254,
      345,
      932,
      866,
      740,
      750,
      601
    ],
    [
      640,
      699,
      427,
      958,
      176,
      402,
      999,
      143,
      424,
      569,
      421,
      617,
      370,
      716,
      8,
      4,
      845,
      260,
      435,
      261,
      288,
      989,
      970,
      466,
      651,
      63,
      459,
      226,
      960,
      802,
      892,
      425,
      889,
      747,
      409,
      944,
      98,
      586,
      214,
      933,
      486,
      992,
      821,
      1004,
      745,
      816,
      868,
      334,
      966,
      586
    ],
    [
      58,
      473,
      230,
      486,
      273,
      371,
      331,
      47,
      618,
      86,
      505,
      465,
      682,
      958,
      803,
      587,
      920,
      34,
      0,
      899,
      427,
      323,
      655,
      304,
      861,
      280,
      839,
      726,
      194,
      117,
      1006,
      103,
      193,
      544,
      768,
      117,
      774,
      413,
      776,
      647,
      144,
      89,
      539,
      612,
      395,
      975,
      527,
      428,
      880,
      96
    ],
    [
      86,
      259,
      384,
      97,
      17,
      140,
      275,
      332,
      193,
      145,
      945,
      395,
      704,
      70,
      434,
      325,
      334,
      325,
      464,
      474,
      843,
      880,
      986,
      490,
      33,
      854,
      716,
      860,
      608,
      96,
      947,
      544,
      589,
      87,
      781,
      841,
      624,
      632,
      984,
      462,
      446,
      460,
      968,
      185,
      602,
      307,
      254,
      121,
      444,
      83
    ],
    [
      289,
      926,
      172,
      273,
      915,
      558,
      406,
      452,
      618,
      416,
      91,
      607,
      356,
      501,
      572,
      264,
      383,
      352,
      733,
      838,
      101,
      607,
      788,
      639,
      912,
      944,
      225,
      812,
      25,
      505,
      480,
      531,
      790,
      342,
      466,
      915,
      33,
      557,
      806,
      653,
      85,
      98,
      470,
      491,
      546,
      763,
      62,
      874,
      83,
      312
    ],
    [
      595,
      27,
      503,
      661,
      923,
      95,
      665,
      995,
      822,
      899,
      69,
      122,
      817,
      63,
      538,
      959,
      200,
      553,
      857,
      544,
      850,
      121,
      1,
      536,
      450,
      354,
      609,
      274,
      9,
      276,
      538,
      894,
      177,
      890,
      318,
      831,
      276,
      103,
      23,
      455,
      947,
      830,
      464,
      53,
      396,
      404,
      342,
      404,
      355,
      687
    ],
    [
      591,
      659,
      215,
      803,
      988,
      573,
      743,
      998,
      23,
      381,
      712,
      312,
      143,
      788,
      781,
      676,
      34,
      745,
      673,
      331,
      659,
      988,
      596,
      919,
      292,
      429,
      136,
      201,
      102,
      592,
      290,
      865,
      556,
      29,
      913,
      632,
      760,
      527,
      36,
      28,
      256,
      15,
      397,
      126,
      634,
      831,
      32,
      633,
      582,
      464
    ],
    [
      69,
      970,
      651,
      392,
      826,
      189,
      88,
      678,
      189,
      574,
      832,
      572,
      803,
      566,
      65,
      1006,
      230,
      105,
      609,
      658,
      904,
      145,
      850,
      702,
      201,
      333,
      795,
      479,
      514,
      823,
      33,
      842,
      835,
      589,
      686,
      332,
      748,
      573,
      111,
      306,
      593,
      421,
      70,
      275,
      505,
      531,
      66,
      288,
      329,
      656
    ],
    [
      225,
      696,
      799,
      680,
      285,
      648,
      14,
      523,
      319,
      634,
      475,
      594,
      691,
      124,
      381,
      269,
      727,
      377,
      759,
      712,
      49,
      602,
      844,
      629,
      108,
      501,
      149,
      298,
      393,
      520,
      280,
      878,
      750,
      503,
      270,
      525,
      863,
      822,
      23,
      920,
      349,
      816,
      61,
      398,
      960,
      116,
      762,
      95,
      745,
      611
    ],
    [
      442,
      440,
      756,
      248,
      309,
      209,
      176,
      225,
      767,
      88,
      562,
      783,
      631,
      690,
      607,
      28,
      106,
      141,
      367,
      305,
      496,
      10,
      735,
      1,
      958,
      354,
      318,
      496,
      419,
      965,
      921,
      753,
      108,
      636,
      862,
      299,
      147,
      277,
      458,
      904,
      232,
      358,
      125,
      1001,
      620,
      32,
      886,
      283,
      891,
      779
    ],
    [
      777,
      513,
      774,
      58,
      774,
      889,
      655,
      552,
      629,
      406,
      605,
      143,
      316,
      600,
      973,
      807,
      1007,
      309,
      322,
      558,
      303,
      623,
      769,
      378,
      622,
      768,
      994,
      758,
      396,
      643,
      162,
      205,
      487,
      11,
      888,
      306,
      837,
      1,
      72,
      829,
      470,
      578,
      608,
      415,
      698,
      882,
      835,
      479,
      762,
      64
    ],
    [
      843,
      691,
      794,
      710,
      590,
      546,
      635,
      62,
      386,
      575,
      147,
      855,
      5,
      927,
      545,
      597,
      615,
      16,
      542,
      160,
      561,
      607,
      768,
      467,
      857,
      236,
      891,
      489,
      776,
      307,
      824,
      853,
      696,
      812,
      936,
      344,
      646,
      555,
      310,
      149,
      804,
      947,
      597,
      310,
      67,
      634,
      882,
      151,
      567,
      639
    ],
    [
      766,
      141,
      336,
      858,
      161,
      700,
      300,
      405,
      828,
      194,
      611,
      881,
      185,
      896,
      335,
      77,
      491,
      33,
      71,
      307,
      576,
      767,
      122,
      723,
      265,
      847,
      136,
      593,
      313,
      257,
      82,
      73,
      345,
      716,
      707,
      175,
      391,
      460,
      79,
      825,
      157,
      333,
      531,
      768,
      399,
      260,
      808,
      854,
      599,
      369
    ],
    [
      322,
      20,
      11,
      566,
      167,
      697,
      1007,
      374,
      402,
      682,
      673,
      132,
      405,
      449,
      439,
      1000,
      149,
      500,
      709,
      330,
      393,
      97,
      276,
      710,
      558,
      20,
      372,
      672,
      985,
      721,
      946,
      761,
      824,
      501,
      676,
      838,
      516,
      780,
      160,
      902,
      803,
      381,
      109,
      131,
      729,
      723,
      800,
      751,
      294,
      841
    ],
    [
      288,
      673,
      835,
      522,
      887,
      637,
      341,
      298,
      364,
      808,
      61,
      967,
      633,
      396,
      734,
      484,
      37,
      98,
      417,
      896,
      696,
      329,
      553,
      951,
      706,
      406,
      562,
      243,
      647,
      339,
      141,
      34,
      474,
      406,
      410,
      240,
      839,
      767,
      978,
      84,
      783,
      574,
      554,
      271,
      439,
      849,
      621,
      315,
      558,
      753
    ],
    [
      553,
      871,
      215,
      544,
      139,
      449,
      590,
      817,
      682,
      512,
      496,
      88,
      239,
      405,
      100,
      1005,
      186,
      606,
      466,
      237,
      189,
      617,
      202,
      582,
      410,
      72,
      362,
      784,
      595,
      840,
      994,
      555,
      276,
      959,
      629,
      299,
      408,
      871,
      644,
      601,
      426,
      102,
      882,
      500,
      30,
      988,
      425,
      635,
      486,
      571
    ],
    [
      175,
      936,
      75,
      100,
      55,
      696,
      526,
      682,
      491,
      527,
      813,
      962,
      492,
      345,
      150,
      912,
      403,
      107,
      490,
      824,
      65,
      452,
      206,
      843,
      506,
      211,
      229,
      908,
      459,
      39,
      327,
      28,
      294,
      702,
      348,
      31,
      36,
      299,
      239,
      890,
      128,
      300,
      902,
      553,
      306,
      91,
      508,
      432,
      871,
      116
    ],
    [
      612,
      497,
      614,
      95,
      500,
      513,
      521,
      206,
      754,
      603,
      927,
      440,
      266,
      48,
      942,
      816,
      332,
      339,
      746,
      907,
      138,
      787,
      522,
      46,
      576,
      742,
      709,
      576,
      329,
      233,
      884,
      184,
      199,
      566,
      313,
      6,
      167,
      805,
      488,
      324,
      110,
      134,
      505,
      352,
      790,
      969,
      213,
      64,
      213,
      454
    ],
    [
      652,
      419,
      776,
      975,
      490,
      145,
      790,
      621,
      507,
      80,
      259,
      701,
      846,
      493,
      375,
      369,
      106,
      14,
      847,
      722,
      437,
      186,
      26,
      831,
      231,
      65,
      856,
      916,
      525,
      192,
      57,
      719,
      222,
      997,
      741,
      904,
      753,
      565,
      174,
      282,
      446,
      325,
      42,
      402,
      1001,
      606,
      82,
      117,
      72,
      602
    ],
    [
      905,
      156,
      775,
      599,
      507,
      97,
      1000,
      80,
      979,
      645,
      233,
      20,
      739,
      465,
      611,
      55,
      245,
      826,
      994,
      226,
      348,
      47,
      338,
      712,
      1007,
      346,
      5,
      901,
      913,
      216,
      318,
      238,
      721,
      996,
      361,
      424,
      980,
      838,
      924,
      921,
      314,
      725,
      990,
      599,
      1007,
      679,
      129,
      10,
      995,
      134
    ],
    [
      245,
      928,
      494,
      471,
      476,
      793,
      550,
      64,
      143,
      527,
      351,
      128,
      950,
      915,
      933,
      638,
      185,
      846,
      79,
      26,
      368,
      318,
      247,
      562,
      79,
      465,
      608,
      520,
      693,
      701,
      310,
      724,
      895,
      67,
      650,
      315,
      187,
      799,
      264,
      405,
      906,
      980,
      603,
      966,
      706,
      386,
      905,
      517,
      852,
      262
    ],
    [
      926,
      919,
      843,
      232,
      13,
      784,
      322,
      980,
      426,
      779,
      210,
      819,
      849,
      79,
      291,
      123,
      411,
      316,
      412,
      616,
      330,
      676,
      476,
      305,
      535,
      338,
      570,
      447,
      380,
      93,
      670,
      365,
      193,
      840,
      313,
      630,
      17,
      897,
      39,
      150,
      497,
      39,
      1,
      610,
      360,
      64,
      987,
      976,
      82,
      969
    ],
    [
      126,
      393,
      561,
      126,
      669,
      567,
      707,
      319,
      9,
      294,
      946,
      597,
      772,
      932,
      775,
      48,
      825,
      300,
      371,
      992,
      20,
      670,
      384,
      642,
      583,
      356,
      181,
      0,
      462,
      964,
      729,
      305,
      995,
      388,
      255,
      175,
      149,
      1005,
      348,
      906,
      633,
      400,
      417,
      847,
      794,
      105,
      973,
      278,
      599,
      756
    ],
    [
      254,
      238,
      714,
      535,
      781,
      969,
      278,
      993,
      285,
      333,
      910,
      295,
      20,
      78,
      286,
      822,
      163,
      509,
      150,
      46,
      786,
      337,
      306,
      74,
      905,
      871,
      767,
      350,
      518,
      68,
      722,
      331,
      258,
      1007,
      241,
      392,
      630,
      477,
      969,
      193,
      524,
      65,
      420,
      357,
      726,
      728,
      537,
      541,
      15,
      512
    ],
    [
      235,
      617,
      90,
      504,
      18,
      358,
      786,
      3,
      793,
      616,
      757,
      203,
      272,
      538,
      583,
      601,
      13,
      921,
      548,
      536,
      473,
      471,
      755,
      379,
      533,
      470,
      755,
      579,
      11,
      901,
      950,
      972,
      863,
      508,
      3,
      311,
      339,
      813,
      380,
      813,
      978,
      610,
      871,
      451,
      706,
      874,
      78,
      704,
      475,
      621
    ],
    [
      429,
      823,
      862,
      611,
      813,
      863,
      816,
      406,
      317,
      379,
      513,
      45,
      626,
      775,
      678,
      890,
      909,
      282,
      774,
      827,
      466,
      559,
      829,
      779,
      140,
      488,
      140,
      400,
      525,
      979,
      485,
      743,
      543,
      77,
      197,
      890,
      367,
      652,
      513,
      164,
      614,
      403,
      663,
      1003,
      531,
      886,
      591,
      496,
      682,
      932
    ],
    [
      964,
      460,
      977,
      143,
      400,
      356,
      10,
      616,
      587,
      255,
      57,
      863,
      273,
      686,
      799,
      68,
      599,
      459,
      904,
      414,
      645,
      674,
      140,
      67,
      684,
      622,
      606,
      499,
      859,
      319,
      507,
      84,
      530,
      43,
      815,
      283,
      29,
      219,
      445,
      549,
      430,
      899,
      293,
      351,
      731,
      734,
      6,
      522,
      574,
      750
    ],
    [
      346,
      818,
      180,
      681,
      386,
      868,
      925,
      487,
      140,
      162,
      535,
      580,
      401,
      151,
      186,
      825,
      198,
      392,
      172,
      237,
      415,
      159,
      488,
      60,
      638,
      189,
      358,
      173,
      672,
      924,
      499,
      692,
      900,
      125,
      586,
      827,
      716,
      767,
      581,
      739,
      286,
      32,
      425,
      284,
      322,
      279,
      30,
      988,
      753,
      120
    ],
    [
      952,
      498,
      996,
      672,
      359,
      641,
      873,
      932,
      833,
      251,
      590,
      1006,
      524,
      552,
      965,
      877,
      826,
      857,
      754,
      81,
      1,
      225,
      395,
      929,
      304,
      668,
      852,
      764,
      60,
      689,
      418,
      696,
      138,
      929,
      145,
      419,
      215,
      512,
      87,
      712,
      39,
      358,
      350,
      783,
      529,
      68,
      651,
      382,
      537,
      364
    ],
    [
      945,
      322,
      423,
      413,
      805,
      84,
      508,
      945,
      16,
      449,
      949,
      726,
      344,
      8,
      990,
      56,
      113,
      221,
      900,
      420,
      643,
      99,
      573,
      797,
      137,
      579,
      984,
      393,
      987,
      680,
      235,
      35,
      265,
      512,
      145,
      69,
      631,
      565,
      138,
      526,
      1001,
      577,
      641,
      206,
      537,
      195,
      216,
      862,
      132,
      750
    ],
    [
      512,
      72,
      318,
      150,
      406,
      311,
      500,
      178,
      786,
      491,
      993,
      847,
      31,
      176,
      897,
      875,
      596,
      879,
      22,
      130,
      863,
      974,
      437,
      212,
      554,
      295,
      47,
      324,
      744,
      535,
      85,
      170,
      398,
      793,
      462,
      944,
      261,
      500,
      474,
      595,
      706,
      584,
      635,
      644,
      38,
      748,
      924,
      994,
      923,
      14
    ],
    [
      603,
      631,
      476,
      937,
      250,
      400,
      297,
      801,
      678,
      377,
      843,
      650,
      159,
      210,
      935,
      137,
      291,
      869,
      68,
      906,
      296,
      47,
      408,
      547,
      780,
      142,
      619,
      242,
      362,
      381,
      914,
      93,
      340,
      80,
      438,
      833,
      291,
      17,
      823,
      72,
      773,
      75,
      303,
      429,
      65,
      211,
      934,
      566,
      18,
      126
    ],
    [
      479,
      248,
      792,
      969,
      811,
      431,
      439,
      378,
      89,
      265,
      383,
      107,
      489,
      471,
      33,
      195,
      719,
      893,
      328,
      234,
      754,
      490,
      747,
      841,
      846,
      928,
      121,
      99,
      402,
      901,
      578,
      397,
      357,
      63,
      809,
      532,
      881,
      899,
      833,
      3,
      480,
      546,
      324,
      671,
      228,
      302,
      688,
      175,
      37,
      849
    ],
    [
      93,
      617,
      650,
      313,
      510,
      129,
      253,
      963,
      1008,
      280,
      621,
      258,
      670,
      911,
      527,
      629,
      58,
      127,
      806,
      570,
      833,
      903,
      212,
      574,
      200,
      512,
      192,
      378,
      751,
      264,
      658,
      447,
      632,
      859,
      997,
      879,
      483,
      821,
      703,
      862,
      527,
      15,
      150,
      416,
      945,
      8,
      35,
      285,
      547,
      303
    ],
    [
      88,
      909,
      308,
      271,
      913,
      467,
      781,
      16,
      512,
      633,
      13,
      143,
      992,
      624,
      486,
      416,
      744,
      464,
      279,
      61,
      381,
      553,
      880,
      209,
      907,
      109,
      422,
      416,
      620,
      422,
      900,
      282,
      506,
      429,
      1007,
      649,
      979,
      278,
      621,
      669,
      425,
      583,
      54,
      499,
      866,
      775,
      410,
      7,
      646,
      341
    ],
    [
      347,
      752,
      397,
      743,
      166,
      906,
      727,
      947,
      772,
      191,
      630,
      567,
      831,
      475,
      14,
      988,
      735,
      325,
      623,
      463,
      598,
      859,
      43,
      208,
      391,
      386,
      690,
      948,
      786,
      463,
      803,
      924,
      480,
      130,
      542,
      915,
      70,
      941,
      15,
      594,
      267,
      532,
      632,
      458,
      126,
      425,
      60,
      396,
      468,
      491
    ],
    [
      972,
      930,
      73,
      746,
      546,
      661,
      581,
      41,
      220,
      497,
      515,
      1002,
      617,
      872,
      891,
      228,
      118,
      749,
      388,
      313,
      937,
      817,
      525,
      358,
      978,
      453,
      1008,
      951,
      423,
      520,
      777,
      0,
      151,
      627,
      262,
      259,
      147,
      741,
      989,
      733,
      847,
      938,
      84,
      493,
      923,
      678,
      359,
      123,
      666,
      354
    ],
    [
      138,
      161,
      261,
      948,
      365,
      401,
      698,
      546,
      744,
      190,
      179,
      392,
      992,
      373,
      777,
      969,
      936,
      606,
      451,
      767,
      743,
      517,
      529,
      495,
      593,
      680,
      651,
      167,
      826,
      290,
      660,
      381,
      926,
      837,
      953,
      831,
      120,
      821,
      195,
      862,
      138,
      975,
      666,
      38,
      294,
      763,
      917,
      222,
      339,
      650
    ],
    [
      32,
      908,
      411,
      601,
      932,
      81,
      695,
      190,
      527,
      663,
      103,
      894,
      18,
      324,
      310,
      405,
      259,
      799,
      505,
      49,
      450,
      779,
      237,
      528,
      494,
      227,
      791,
      278,
      776,
      806,
      698,
      595,
      445,
      764,
      908,
      839,
      816,
      626,
      428,
      289,
      478,
      874,
      997,
      683,
      4,
      787,
      427,
      423,
      432,
      526
    ],
    [
      745,
      939,
      661,
      234,
      3,
      360,
      965,
      389,
      301,
      845,
      509,
      802,
      175,
      242,
      697,
      706,
      111,
      161,
      467,
      809,
      164,
      849,
      473,
      937,
      837,
      591,
      145,
      497,
      676,
      942,
      222,
      460,
      240,
      324,
      415,
      444,
      686,
      513,
      732,
      900,
      317,
      134,
      770,
      286,
      375,
      627,
      214,
      152,
      257,
      775
    ],
    [
      433,
      64,
      25,
      486,
      494,
      143,
      106,
      686,
      322,
      209,
      867,
      693,
      36,
      382,
      231,
      673,
      336,
      608,
      82,
      743,
      598,
      48,
      366,
      834,
      309,
      468,
      382,
      181,
      313,
      680,
      589,
      760,
      125,
      229,
      406,
      844,
      639,
      372,
      657,
      598,
      665,
      520,
      705,
      635,
      120,
      943,
      36,
      947,
      741,
      100
    ],
    [
      895,
      424,
      215,
      277,
      374,
      340,
      293,
      658,
      52,
      860,
      540,
      915,
      41,
      685,
      483,
      705,
      932,
      321,
      862,
      682,
      67,
      498,
      936,
      274,
      377,
      274,
      147,
      674,
      570,
      142,
      1001,
      761,
      957,
      649,
      511,
      752,
      52,
      175,
      743,
      872,
      846,
      338,
      399,
      291,
      354,
      234,
      626,
      144,
      962,
      943
    ],
    [
      890,
      153,
      308,
      743,
      104,
      366,
      997,
      160,
      200,
      190,
      456,
      149,
      203,
      355,
      513,
      690,
      802,
      471,
      323,
      404,
      443,
      297,
      346,
      70,
      987,
      358,
      35,
      910,
      40,
      235,
      294,
      561,
      167,
      637,
      697,
      777,
      946,
      870,
      735,
      433,
      702,
      366,
      462,
      511,
      182,
      798,
      678,
      996,
      417,
      632
    ],
    [
      79,
      7,
      420,
      167,
      784,
      402,
      856,
      92,
      15,
      971,
      292,
      440,
      953,
      773,
      925,
      972,
      314,
      315,
      640,
      805,
      488,
      555,
      666,
      624,
      785,
      740,
      371,
      249,
      876,
      594,
      55,
      51,
      537,
      485,
      37,
      267,
      688,
      609,
      159,
      457,
      615,
      644,
      184,
      241,
      440,
      399,
      677,
      282,
      612,
      32
    ],
    [
      903,
      946,
      386,
      43,
      437,
      364,
      34,
      238,
      521,
      587,
      406,
      604,
      147,
      843,
      342,
      586,
      865,
      209,
      888,
      632,
      768,
      857,
      497,
      506,
      554,
      460,
      443,
      817,
      358,
      39,
      872,
      182,
      941,
      617,
      721,
      519,
      604,
      486,
      907,
      156,
      530,
      365,
      860,
      705,
      243,
      124,
      128,
      270,
      449,
      198
    ],
    [
      633,
      59,
      855,
      97,
      860,
      411,
      943,
      182,
      435,
      535,
      827,
      750,
      133,
      44,
      448,
      496,
      259,
      423,
      855,
      664,
      858,
      831,
      613,
      608,
      425,
      223,
      967,
      495,
      225,
      658,
      938,
      838,
      631,
      737,
      602,
      324,
      282,
      641,
      567,
      152,
      722,
      224,
      579,
      592,
      678,
      335,
      158,
      266,
      622,
      484
    ],
    [
      597,
      988,
      272,
      451,
      152,
      929,
      613,
      992,
      358,
      729,
      387,
      243,
      70,
      285,
      286,
      175,
      188,
      1008,
      678,
      879,
      821,
      290,
      41,
      958,
      428,
      321,
      435,
      2,
      909,
      671,
      962,
      301,
      45,
      993,
      561,
      236,
      478,
      724,
      538,
      716,
      154,
      659,
      63,
      1003,
      416,
      801,
      417,
      136,
      411,
      84
    ],
    [
      630,
      853,
      759,
      372,
      667,
      863,
      973,
      466,
      8,
      472,
      540,
      148,
      224,
      655,
      520,
      255,
      271,
      447,
      700,
      31,
      920,
      636,
      55,
      619,
      718,
      1008,
      133,
      584,
      46,
      97,
      792,
      108,
      298,
      197,
      782,
      546,
      83,
      345,
      904,
      77,
      679,
      340,
      912,
      465,
      613,
      632,
      15,
      348,
      66,
      66
    ],
    [
      614,
      707,
      437,
      924,
      46,
      319,
      694,
      210,
      564,
      545,
      965,
      457,
      76,
      987,
      433,
      68,
      293,
      75,
      290,
      714,
      130,
      611,
      977,
      128,
      651,
      284,
      442,
      249,
      964,
      369,
      123,
      945,
      683,
      86,
      960,
      680,
      195,
      528,
      978,
      683,
      712,
      433,
      587,
      848,
      158,
      526,
      138,
      656,
      336,
      231
    ],
    [
      615,
      750,
      157,
      393,
      467,
      156,
      770,
      572,
      106,
      859,
      815,
      770,
      492,
      712,
      968,
      802,
      382,
      11,
      747,
      676,
      204,
      828,
      350,
      675,
      788,
      107,
      126,
      632,
      300,
      213,
      822,
      781,
      33,
      372,
      302,
      877,
      246,
      301,
      428,
      986,
      349,
      545,
      676,
      485,
      591,
      422,
      840,
      576,
      514,
      192
    ],
    [
      598,
      711,
      817,
      398,
      200,
      413,
      791,
      751,
      794,
      238,
      919,
      623,
      354,
      595,
      538,
      452,
      616,
      434,
      977,
      449,
      874,
      458,
      316,
      281,
      283,
      106,
      442,
      308,
      327,
      550,
      977,
      534,
      159,
      627,
      421,
      556,
      217,
      915,
      130,
      65,
      921,
      523,
      211,
      418,
      608,
      731,
      701,
      807,
      232,
      759
    ],
    [
      393,
      312,
      929,
      20,
      462,
      420,
      143,
      659,
      616,
      715,
      386,
      81,
      360,
      401,
      565,
      138,
      302,
      591,
      678,
      52,
      219,
      590,
      525,
      389,
      991,
      427,
      320,
      786,
      560,
      274,
      17,
      174,
      751,
      529,
      476,
      811,
      773,
      764,
      775,
      51,
      279,
      752,
      51,
      477,
      125,
      470,
      363,
      719,
      137,
      312
    ],
    [
      318,
      894,
      863,
      631,
      487,
      542,
      783,
      553,
      359,
      315,
      276,
      945,
      90,
      561,
      23,
      834,
      332,
      365,
      84,
      336,
      412,
      500,
      668,
      384,
      749,
      623,
      56,
      758,
      777,
      483,
      370,
      234,
      686,
      330,
      490,
      885,
      352,
      105,
      475,
      963,
      400,
      955,
      841,
      906,
      367,
      983,
      918,
      447,
      116,
      2
    ],
    [
      364,
      660,
      464,
      546,
      251,
      486,
      428,
      263,
      195,
      274,
      21,
      213,
      787,
      247,
      359,
      702,
      113,
      806,
      767,
      467,
      599,
      176,
      846,
      92,
      839,
      515,
      835,
      560,
      855,
      749,
      783,
      94,
      845,
      71,
      86,
      915,
      434,
      172,
      705,
      170,
      303,
      40,
      73,
      106,
      736,
      785,
      575,
      705,
      800,
      790
    ],
    [
      614,
      900,
      363,
      366,
      404,
      895,
      376,
      761,
      408,
      866,
      784,
      455,
      784,
      741,
      702,
      300,
      238,
      856,
      472,
      320,
      262,
      257,
      20,
      110,
      939,
      704,
      106,
      187,
      368,
      56,
      72,
      272,
      31,
      118,
      396,
      162,
      934,
      337,
      696,
      171,
      826,
      143,
      837,
      511,
      493,
      852,
      173,
      995,
      40,
      224
    ],
    [
      140,
      682,
      372,
      845,
      959,
      182,
      992,
      48,
      7,
      287,
      693,
      420,
      281,
      629,
      4,
      494,
      949,
      956,
      696,
      302,
      827,
      365,
      404,
      933,
      30,
      58,
      661,
      864,
      295,
      791,
      602,
      189,
      160,
      716,
      215,
      104,
      696,
      82,
      721,
      65,
      495,
      268,
      955,
      791,
      106,
      558,
      598,
      30,
      338,
      750
    ],
    [
      678,
      408,
      534,
      459,
      606,
      755,
      226,
      52,
      650,
      424,
      48,
      239,
      380,
      497,
      782,
      208,
      987,
      48,
      883,
      236,
      506,
      166,
      810,
      275,
      803,
      822,
      815,
      987,
      767,
      233,
      252,
      691,
      634,
      497,
      88,
      433,
      864,
      396,
      148,
      127,
      703,
      166,
      662,
      129,
      685,
      116,
      138,
      357,
      1002,
      102
    ],
    [
      110,
      93,
      534,
      380,
      436,
      565,
      833,
      561,
      67,
      576,
      348,
      712,
      488,
      543,
      966,
      736,
      675,
      797,
      334,
      661,
      850,
      336,
      639,
      295,
      959,
      46,
      625,
      329,
      475,
      214,
      456,
      281,
      285,
      234,
      62,
      170,
      223,
      929,
      791,
      68,
      968,
      519,
      707,
      788,
      536,
      620,
      682,
      984,
      13,
      157
    ],
    [
      742,
      354,
      174,
      117,
      225,
      839,
      618,
      313,
      246,
      58,
      163,
      844,
      357,
      756,
      254,
      663,
      102,
      389,
      523,
      76,
      513,
      187,
      548,
      202,
      554,
      650,
      298,
      827,
      865,
      683,
      415,
      884,
      97,
      307,
      695,
      152,
      704,
      547,
      433,
      650,
      149,
      139,
      447,
      971,
      546,
      155,
      738,
      734,
      925,
      398
    ],
    [
      897,
      228,
      461,
      224,
      112,
      821,
      459,
      242,
      703,
      978,
      384,
      395,
      337,
      495,
      481,
      553,
      990,
      158,
      778,
      875,
      659,
      686,
      60,
      638,
      550,
      792,
      988,
      44,
      318,
      3,
      547,
      46,
      69,
      737,
      643,
      635,
      648,
      516,
      777,
      392,
      123,
      162,
      33,
      763,
      852,
      682,
      838,
      776,
      299,
      747
    ],
    [
      330,
      416,
      477,
      960,
      669,
      280,
      313,
      193,
      15,
      7,
      306,
      10,
      457,
      483,
      693,
      219,
      206,
      567,
      906,
      416,
      428,
      598,
      415,
      457,
      475,
      968,
      633,
      591,
      578,
      351,
      624,
      473,
      48,
      951,
      192,
      112,
      498,
      74,
      201,
      950,
      937,
      873,
      865,
      799,
      900,
      134,
      645,
      358,
      995,
      257
    ],
    [
      859,
      794,
      163,
      924,
      649,
      606,
      35,
      880,
      46,
      765,
      13,
      26,
      262,
      827,
      958,
      825,
      388,
      434,
      105,
      969,
      50,
      245,
      591,
      710,
      338,
      705,
      295,
      77,
      28,
      117,
      887,
      577,
      414,
      138,
      666,
      200,
      857,
      107,
      2,
      291,
      207,
      42,
      261,
      101,
      398,
      778,
      799,
      734,
      565,
      42
    ],
    [
      562,
      678,
      510,
      522,
      16,
      921,
      349,
      873,
      323,
      553,
      852,
      82,
      221,
      776,
      784,
      919,
      894,
      533,
      702,
      711,
      277,
      158,
      277,
      253,
      715,
      177,
      900,
      254,
      130,
      16,
      880,
      56,
      79,
      409,
      793,
      651,
      698,
      308,
      366,
      535,
      684,
      405,
      462,
      612,
      165,
      375,
      429,
      937,
      642,
      105
    ],
    [
      591,
      156,
      652,
      825,
      383,
      523,
      667,
      358,
      225,
      766,
      891,
      846,
      974,
      1001,
      589,
      806,
      541,
      290,
      936,
      526,
      714,
      838,
      852,
      333,
      162,
      393,
      598,
      138,
      970,
      990,
      77,
      16,
      955,
      821,
      33,
      307,
      926,
      627,
      709,
      644,
      932,
      357,
      735,
      149,
      652,
      649,
      33,
      58,
      773,
      320
    ],
    [
      366,
      397,
      727,
      528,
      261,
      515,
      122,
      14,
      310,
      445,
      280,
      545,
      303,
      330,
      574,
      428,
      727,
      650,
      953,
      74,
      857,
      157,
      763,
      781,
      693,
      901,
      206,
      292,
      838,
      897,
      122,
      597,
      546,
      724,
      309,
      781,
      74,
      610,
      593,
      717,
      393,
      817,
      429,
      154,
      112,
      853,
      236,
      224,
      461,
      801
    ],
    [
      922,
      332,
      885,
      726,
      236,
      238,
      861,
      285,
      170,
      75,
      63,
      872,
      198,
      577,
      5,
      309,
      123,
      575,
      799,
      817,
      457,
      368,
      914,
      442,
      281,
      499,
      555,
      337,
      228,
      812,
      402,
      516,
      195,
      347,
      863,
      942,
      307,
      436,
      251,
      405,
      764,
      794,
      31,
      769,
      748,
      409,
      331,
      939,
      743,
      371
    ],
    [
      988,
      511,
      935,
      509,
      494,
      532,
      916,
      118,
      846,
      12,
      644,
      43,
      121,
      811,
      178,
      146,
      140,
      538,
      155,
      189,
      901,
      532,
      825,
      915,
      290,
      442,
      497,
      192,
      170,
      815,
      841,
      864,
      310,
      163,
      350,
      616,
      442,
      187,
      808,
      171,
      229,
      861,
      831,
      798,
      825,
      189,
      810,
      579,
      957,
      990
    ],
    [
      830,
      390,
      734,
      470,
      998,
      466,
      276,
      466,
      906,
      704,
      409,
      610,
      296,
      25,
      504,
      138,
      427,
      5,
      35,
      435,
      103,
      314,
      290,
      427,
      59,
      123,
      664,
      110,
      616,
      982,
      128,
      576,
      880,
      989,
      711,
      199,
      35,
      991,
      179,
      412,
      852,
      776,
      309,
      121,
      19,
      974,
      446,
      759,
      814,
      1006
    ],
    [
      104,
      607,
      167,
      131,
      707,
      395,
      819,
      203,
      7,
      675,
      832,
      798,
      647,
      913,
      158,
      378,
      921,
      743,
      776,
      348,
      291,
      153,
      123,
      598,
      1000,
      575,
      116,
      1003,
      417,
      153,
      475,
      644,
      179,
      523,
      726,
      281,
      307,
      179,
      241,
      320,
      948,
      160,
      640,
      207,
      801,
      13,
      350,
      401,
      141,
      440
    ],
    [
      633,
      996,
      666,
      944,
      858,
      133,
      87,
      616,
      354,
      614,
      805,
      814,
      201,
      295,
      48,
      968,
      822,
      176,
      390,
      17,
      418,
      534,
      631,
      341,
      590,
      758,
      290,
      703,
      375,
      541,
      706,
      253,
      976,
      203,
      408,
      724,
      92,
      559,
      386,
      130,
      386,
      842,
      413,
      159,
      516,
      995,
      167,
      911,
      601,
      135
    ],
    [
      536,
      462,
      361,
      289,
      274,
      312,
      762,
      594,
      492,
      488,
      152,
      758,
      27,
      583,
      632,
      317,
      790,
      434,
      411,
      9,
      782,
      60,
      355,
      882,
      379,
      957,
      715,
      332,
      1,
      181,
      965,
      932,
      954,
      89,
      174,
      751,
      250,
      282,
      709,
      892,
      50,
      919,
      774,
      841,
      504,
      246,
      544,
      231,
      183,
      352
    ],
    [
      356,
      210,
      629,
      343,
      378,
      462,
      906,
      138,
      709,
      719,
      80,
      445,
      884,
      498,
      922,
      69,
      987,
      689,
      93,
      936,
      217,
      708,
      312,
      162,
      707,
      110,
      114,
      540,
      589,
      387,
      549,
      932,
      500,
      52,
      892,
      452,
      238,
      98,
      482,
      702,
      541,
      955,
      612,
      629,
      638,
      530,
      744,
      55,
      617,
      765
    ],
    [
      595,
      652,
      436,
      247,
      881,
      719,
      199,
      163,
      427,
      582,
      919,
      395,
      747,
      169,
      720,
      730,
      215,
      661,
      47,
      951,
      324,
      574,
      685,
      812,
      773,
      877,
      833,
      38,
      991,
      197,
      392,
      242,
      146,
      228,
      588,
      978,
      255,
      548,
      501,
      158,
      525,
      318,
      783,
      754,
      441,
      815,
      175,
      551,
      589,
      462
    ],
    [
      793,
      788,
      17,
      79,
      771,
      826,
      963,
      363,
      787,
      700,
      253,
      851,
      769,
      874,
      918,
      39,
      862,
      561,
      329,
      619,
      330,
      769,
      489,
      921,
      990,
      111,
      32,
      996,
      499,
      230,
      377,
      72,
      582,
      762,
      320,
      990,
      730,
      856,
      376,
      344,
      585,
      885,
      577,
      509,
      479,
      100,
      143,
      476,
      701,
      612
    ],
    [
      532,
      32,
      587,
      23,
      914,
      17,
      289,
      124,
      200,
      434,
      46,
      314,
      449,
      952,
      443,
      832,
      247,
      967,
      52,
      539,
      510,
      885,
      20,
      522,
      965,
      443,
      214,
      245,
      968,
      265,
      374,
      193,
      979,
      239,
      30,
      243,
      90,
      336,
      857,
      107,
      189,
      939,
      429,
      869,
      709,
      758,
      533,
      449,
      714,
      11
    ],
    [
      936,
      130,
      945,
      253,
      245,
      714,
      547,
      850,
      726,
      896,
      853,
      965,
      975,
      422,
      598,
      757,
      619,
      736,
      365,
      0,
      723,
      853,
      581,
      899,
      552,
      206,
      798,
      871,
      725,
      348,
      443,
      497,
      173,
      425,
      467,
      170,
      189,
      634,
      618,
      686,
      635,
      769,
      849,
      725,
      104,
      159,
      779,
      603,
      235,
      317
    ],
    [
      817,
      335,
      948,
      66,
      792,
      466,
      608,
      305,
      223,
      227,
      325,
      2,
      192,
      726,
      559,
      551,
      393,
      963,
      1006,
      248,
      84,
      469,
      670,
      36,
      367,
      134,
      729,
      736,
      45,
      759,
      340,
      142,
      475,
      175,
      576,
      552,
      1007,
      61,
      372,
      139,
      977,
      488,
      477,
      596,
      267,
      145,
      582,
      296,
      570,
      271
    ]
  ],
  "b": [
    863,
    261,
    601,
    377,
    832,
    974,
    687,
    799,
    638,
    612,
    71,
    713,
    149,
    332,
    870,
    212,
    29,
    464,
    714,
    253,
    803,
    274,
    656,
    774,
    368,
    691,
    153,
    306,
    873,
    954,
    73,
    732,
    78,
    533,
    295,
    829,
    118,
    703,
    757,
    703,
    193,
    626,
    278,
    684,
    43,
    415,
    729,
    489,
    797,
    692,
    40,
    262,
    406,
    559,
    994,
    156,
    434,
    639,
    671,
    60,
    888,
    141,
    320,
    961,
    523,
    43,
    960,
    282,
    475,
    474,
    523,
    121,
    923,
    637,
    20,
    154,
    986,
    880,
    943,
    663,
    677,
    283,
    271,
    495,
    105,
    612,
    483,
    650,
    79,
    398,
    386,
    176,
    356,
    242,
    461,
    584,
    751,
    46,
    322,
    810
  ]
}
json

前半部分要你找个Hamilton回路,逐结点扩展后发过去会告诉你当前扩展的结点对不对,简单DFS不作赘述。

后半部分是经典的 As+e=b(modq)As+e=b\pmod{q} 形式的LWE,知道A、b、q的同时会把e的绝对值给你。但是模数很小同时和error非常接近,这一点最初把我带偏了,以为格不出来,所以我最初是想办法取了50个方程求出A的逆之后把s表示出来,然后一半s的分量挪到等式另一边,这样就可以尝试MITM爆破系数。

后来试了试发现用上NumPy之后单核也要180h左右并且非常吃内存才想到这似乎不是正解XD

其实还是得格,用优化后的primal attack再在格的下面添上e就好了。

前面优化的部分参考鸡块的blog,后半参考exp吧,懒得打公式了(

exp.py
from sage.all import (
    matrix,
    vector,
    ZZ,
    block_matrix,
    diagonal_matrix,
    Zmod,
    identity_matrix,
)
import subprocess
import json
from pwn import context, remote, log
from re import findall
import os

context.log_level = "info"


def solve_pow(command) -> str:
    log.info(f"Running PoW command: {command}")
    ret = subprocess.run(
        command,
        shell=True,
        stdout=subprocess.PIPE,
        stderr=subprocess.PIPE,
        encoding="utf-8",
        executable="/bin/bash",
    )
    if ret.returncode == 0:
        log.success(f"PoW solver success: {ret.stdout.strip()}")
        return ret.stdout.strip()
    else:
        log.error(f"PoW solver failed: {ret.stderr.strip()}")
    raise Exception(f"Command failed: {command}\n{ret.stderr.strip()}")


def check_path(path_segment: list) -> dict:
    payload = {"command": "check_path", "segment": path_segment}
    io.sendline(json.dumps(payload).encode())
    response_raw = io.recvline()
    return json.loads(response_raw.decode())


def flatter(M):
    # compile https://github.com/keeganryan/flatter and put it in $PATH
    z = "[[" + "]\n[".join(" ".join(map(str, row)) for row in M) + "]]"
    env = os.environ.copy()
    env["OMP_NUM_THREADS"] = "8"  # 控制线程数量
    ret = subprocess.check_output(["flatter"], input=z.encode(), env=env)
    return matrix(M.nrows(), M.ncols(), map(int, findall(rb"-?\d+", ret)))


io = remote("filtermaze.2025.ctfcompetition.com", 1337, ssl=False)
io.recvuntil(b"the solver with:\n")
cmd = io.recvline().strip().decode()
res = solve_pow(cmd)
io.sendlineafter(b"Solution? ", res.encode())
io.recvuntil(b'{"command": "get_flag", "lwe_secret_s": [...] }\n')
log.info("PoW accepted. Starting maze traversal.")

# Searching the secret path
with open("graph.json", "r") as f:
    graph_str_keys = json.load(f)
graph = {int(k): v for k, v in graph_str_keys.items()}
secret_path = []
all_nodes = sorted(list(graph.keys()))
for node in all_nodes:
    log.debug(f"Testing node {node} as the starting point...")
    resp = check_path([node])
    if resp.get("status") == "valid_prefix":
        secret_path.append(node)
        log.success(f"Found starting node: {node}")
        break

if not secret_path:
    log.error("Failed to find the starting node")
log.info("Starting to extend the path...")
lwe_error_magnitudes = []
while True:
    current_node = secret_path[-1]
    neighbors = graph.get(current_node, [])

    found_next_node = False
    for neighbor in sorted(neighbors):
        # ensure Hamilton path
        if neighbor in secret_path:
            continue

        test_path = secret_path + [neighbor]
        resp = check_path(test_path)
        status = resp.get("status")

        if status == "valid_prefix":
            secret_path.append(neighbor)
            log.debug(f"Path extended: {secret_path}")
            found_next_node = True
            break
        elif status == "path_complete":
            secret_path.append(neighbor)
            log.success(f"Found the full secret path!")
            lwe_error_magnitudes = resp.get("lwe_error_magnitudes")
            log.success("Received LWE error magnitudes.")
            found_next_node = True
            break

    if not found_next_node:
        log.error(
            f"Could not find the next node from {current_node}. Path so far: {secret_path}"
        )
        break

    if lwe_error_magnitudes:
        break

log.info("Maze Traversal Complete")
log.info(f"Final Secret Path ({len(secret_path)} nodes): {secret_path}")
log.info(
    f"LWE Error Magnitudes (m={len(lwe_error_magnitudes)}): {lwe_error_magnitudes}"
)
with open("lwe_error_magnitudes.json", "w") as f:
    json.dump({"lwe_error_magnitudes": lwe_error_magnitudes}, f, indent=2)
with open("lwe_pub_params.json", "r") as f:
    lwe_pub_params = json.load(f)
with open("lwe_error_magnitudes.json") as f:
    lwe_error_params = json.load(f)

# Solving LWE
n = lwe_pub_params["lwe_n"]
m = lwe_pub_params["lwe_m"]
q = lwe_pub_params["lwe_q"]
A = matrix(ZZ, lwe_pub_params["A"])
b = vector(lwe_pub_params["b"])
lwe_error_magnitudes = lwe_error_params["lwe_error_magnitudes"]
mags_vec = vector(ZZ, lwe_error_magnitudes)
log.debug(f"Parameters: n={n}, m={m}, q={q}")
R1 = block_matrix(
    ZZ, [[matrix(Zmod(q), A).T.echelon_form().change_ring(ZZ), matrix.zero(n, m + 1)]]
)
R2 = block_matrix(
    ZZ,
    [
        [
            matrix.zero(m - n, n).augment(matrix.identity(m - n) * q),
            matrix.zero(m - n, m + 1),
        ],
    ],
)
R3 = block_matrix(ZZ, [[matrix(ZZ, b), 1, matrix([0] * m)]])
R4 = block_matrix(
    ZZ, [[diagonal_matrix(ZZ, [*mags_vec]), matrix.zero(m, 1), identity_matrix(m)]]
)
L = block_matrix(ZZ, [[R1], [R2], [R3], [R4]])
L[:, :m] *= 2**64

# LLL is enough but I prefer flatter :)
M = flatter(L)
cands = []

# Appending diagonal_matrix(e) to the lower-left of the lattice yields the signs in rows [m + 1 :]
for row in M:
    if row[:m] == 0:
        cands.append(row[m + 1 :])
res = list(matrix(cands)[0])
assert all(abs(c) == 1 for c in res)
Zq = Zmod(q)
A = matrix(Zq, lwe_pub_params["A"])
b = vector(Zq, lwe_pub_params["b"])
error_mags = vector(ZZ, lwe_error_magnitudes)
error_signs = vector(ZZ, res)

e_list_ZZ = [error_mags[i] * error_signs[i] for i in range(m)]
e_vec_ZZ = vector(ZZ, e_list_ZZ)
e_vec_Zq = vector(Zq, e_vec_ZZ)
# A*s = b - e (mod q)
target_vector_t = b - e_vec_Zq
log.debug("Solving the linear system A*s = t (mod q)...")

try:
    s = A.solve_right(target_vector_t)
    log.success("System solved successfully!")
    s_list = [int(x) for x in s]
except ValueError as e:
    log.error(f"[-] Could not solve the linear system. Error: {e}")
with open("lwe_secret_s.json", "w") as f:
    json.dump({"lwe_secret_s": s_list}, f, indent=2)
with open("lwe_secret_s.json", "r") as f:
    secret_data = json.load(f)
lwe_secret_s = secret_data["lwe_secret_s"]
flag_payload = {"command": "get_flag", "lwe_secret_s": lwe_secret_s}
io.sendline(json.dumps(flag_payload).encode())

log.success("Flag response received:")
flag_response = io.recvall()
print(flag_response.decode())
io.close()
# {"status": "success", "flag": "CTF{d4_sup3r_sh0rt_3rr0r_v3ct0r_1s_th3_k3y}"}
python

后面试验发现就用原版primal attack的格把e放缩一下也是可以的,将每个 A[i]A[i]b[i]b[i] 乘以对应的 pow(e[i],1,q)\text{pow}(e[i], -1, q) 就能将误差范围缩小到 [1,1](modq)[-1, 1]\pmod{q}

Misc#

*bpfbox#

赛中差一点解出来,赛后才upsolved。

还是想复杂了

main.go
package main

import (
        "bufio"
        "context"
        "fmt"
        "os"
        "os/exec"
        "strconv"
        "strings"
        "syscall"
        "time"
)

const probeText = `
BEGIN {
        printf("ready\n")
}

fentry:vmlinux:security_create_user_ns {
        signal(KILL);
}

fentry:vmlinux:security_file_open {
        $inode = args->file->f_inode;
        $d = $inode->i_sb->s_dev;
        $i = $inode->i_ino;

        if ($d == $1 && $i == $2) {
                signal(KILL);
        }
}
`

func getProbeParams(filename string) (uint64, uint64, error) {
        info, err := os.Stat("/flag.txt")
        if err != nil {
                return 0, 0, err
        }

        stat, ok := info.Sys().(*syscall.Stat_t)
        if !ok {
                return 0, 0, fmt.Errorf("expected Stat_t, but was: %s", info.Sys())
        }

        return stat.Dev, stat.Ino, nil
}

func runTracer(ctx context.Context, dev, ino uint64, rdy chan struct{}, errs chan error) {
        cmd := exec.CommandContext(ctx, "/bin/bpftrace", "--unsafe", "-e", probeText, strconv.FormatUint(dev, 10), strconv.FormatUint(ino, 10))
        // cmd.Wait will close the reader automatically
        reader, err := cmd.StdoutPipe()
        if err != nil {
                errs <- err
                return
        }

        err = cmd.Start()
        if err != nil {
                errs <- err
                return
        }

        // wait for the probe to be ready
        scanner := bufio.NewScanner(reader)
        for scanner.Scan() {
                if strings.Contains(scanner.Text(), "ready") {
                        break
                }
        }

        close(rdy)
        err = cmd.Wait()
        if err != nil {
                panic(err)
        }
}

func mountFilesystems() error {
        if err := syscall.Mount("devtmpfs", "/dev", "devtmpfs", 0, ""); err != nil {
                return fmt.Errorf("error mounting /dev: %s", err)
        }

        if err := os.Mkdir("/proc", 0555); err != nil {
                return fmt.Errorf("error creating /proc: %s", err)
        }

        if err := syscall.Mount("proc", "/proc", "proc", 0, ""); err != nil {
                return fmt.Errorf("error mounting /proc: %s", err)
        }

        if err := os.Mkdir("/sys", 0555); err != nil {
                return fmt.Errorf("error creating /sys: %s", err)
        }

        if err := syscall.Mount("sysfs", "/sys", "sysfs", 0, ""); err != nil {
                return fmt.Errorf("error mounting /sys: %s", err)
        }

        if err := syscall.Mount("tracefs", "/sys/kernel/tracing", "tracefs", 0, ""); err != nil {
                return fmt.Errorf("error mounting /sys/kernel/tracing: %s", err)
        }

        if err := syscall.Mount("debugfs", "/sys/kernel/debug", "debugfs", 0, ""); err != nil {
                return fmt.Errorf("error mounting /sys/kernel/debug: %s", err)
        }

        if err := os.Mkdir("/tmp", 0555); err != nil {
                return fmt.Errorf("error creating /tmp: %s", err)
        }

        if err := syscall.Mount("tmpfs", "/tmp", "tmpfs", syscall.MS_NOEXEC|syscall.MS_NODEV|syscall.MS_NOSUID, ""); err != nil {
                return fmt.Errorf("error mounting /tmp: %s", err)
        }

        return nil
}

func shutdown() error {
        return syscall.Reboot(syscall.LINUX_REBOOT_CMD_POWER_OFF)
}

func spawnShell(ctx context.Context) error {
        withTimeout, cancel := context.WithTimeout(ctx, time.Minute)
        defer cancel()

        cmd := exec.CommandContext(withTimeout, "/bin/sh")
        cmd.SysProcAttr = &syscall.SysProcAttr{
                Credential: &syscall.Credential{Uid: 99999, Gid: 99999},
                Setpgid:    true,
                Pdeathsig:  syscall.SIGKILL,
        }
        cmd.Stdout = os.Stdout
        cmd.Stdin = os.Stdin
        cmd.Stderr = os.Stderr
        if err := cmd.Start(); err != nil {
                return err
        }

        if err := cmd.Wait(); err != nil {
                fmt.Println("command failed:", err)
        }
        return nil
}

func main() {
        if err := mountFilesystems(); err != nil {
                panic(err)
        }

        dev, ino, err := getProbeParams("/flag.txt")
        if err != nil {
                panic(err)
        }

        ctx, cancel := context.WithCancel(context.Background())
        defer cancel()

        rdy := make(chan struct{})
        errs := make(chan error)
        go runTracer(ctx, dev, ino, rdy, errs)

        select {
        case err = <-errs:
                panic(err)
        case <-rdy:
        }

        if err := spawnShell(ctx); err != nil {
                panic(err)
        }

        if err := shutdown(); err != nil {
                panic(err)
        }
        panic("unreachable")
}
go

Linux内核题,用BPF Probe追踪并signal SIGKILL杀掉所有尝试读取flag.txt的进程。

这里有个小bug,靶机里实际上是signal SIGINT

连上靶机后看到内核版本是6.12.33,我最初以为是利用CVE-2025-21756去提权然后搞事情,试了试很快就领教到了kctf jail的严密,想上传文件RCE对我这种三脚猫水平而言几乎不可能。

然后想到可能是race——我可以在一个进程打开文件之后、被杀掉之前用另一个进程读这个进程的fd,说不定就可以读到flag。但是很遗憾构造的payload没打通QQ

完赛后回来看了看这题,想到说其实最简单的race说不定就可以:

while true; do ( cat flag.txt & ); done

试了下还真的能通🥲

我真傻,真的

进一步地,其实直接提示GPT试试看race的话也会吐出一个可用的exp:

好总结

for i in $(seq 1 100); do
  cat /flag.txt &
done
sh

但是赛中我说的太多了好像反而把大模型带偏了TT

错在Swizzer

2025 GoogleCTF
https://blog.swizzer.cc/blog/2025-googlectf
Author Swizzer
Published at June 28, 2025