Saturday, 20 December 2025

Cryptographic Application of Building Block Numbers

Given that any number up to 243373 can be represented using only the building blocks 1, 2, 4, 11, 25, 64, 171, 569, 3406 and 27697, I thought that capital letters could be used to represent these building block numbers: A for 1, B or 2, C for 4, D for 11, E for 25, F for 64, G for 171, H for 569, I for 3406 and J for 27697. 

With the input of a given natural number, I asked Gemini to output the building block representations using these letters, retaining brackets and any + signs but omitting any multiplication signs (as in algebra). Thus 12 = (1 + 2) * 4 would become (A + B) C. I'm was thinking in terms of cryptography where the number will be disguised using the alphabet cyphers just described and only be dicipherable using the key (A=1, B=2 and C=4 etc.). The program only needs to deal with building blocks up to 27697. 


Infographic generated by Nano Bananas using this blog's content.

Gemini duly came up with the Python program and Figure 1 shows the output:

Figure 1:
see Python code below

The program times out in SageMathCell so I've included the Python code below for reference. If making practical use of this form of encryption, one of these representations would be chosen at random and used to replace the decimal number.

*******************************
PYTHON CODE
(courtesy of Gemini)

import itertools

def solve_oeis_crypto_cipher(target):
    """
    Finds algebraic representations of 'target' using OEIS A086424 terms.
    Outputs the result using Letter Ciphers (A=1, B=2, ...).
    
    Rules:
    - A=1, B=2, C=4, D=11, E=25, F=64, G=171, H=569, I=3406, J=27697
    - Multiplication (*) is implicit (omitted). e.g., A*B -> AB
    - Addition (+) is retained.
    - Brackets included only when necessary.
    """
    
    # 1. Define the Cipher Mapping
    # We only go up to J (27697) as requested
    term_map = {
        1: 'A', 2: 'B', 4: 'C', 11: 'D', 25: 'E', 
        64: 'F', 171: 'G', 569: 'H', 3406: 'I', 27697: 'J'
    }
    
    full_sequence = sorted(term_map.keys())
    
    # Filter terms to only those small enough to be useful
    terms = [x for x in full_sequence if x <= target]
    n = len(terms)
    
    # DP State: dp[mask][value] = set of Canonical Tuples
    # Tuple Structure: ('TYPE', (operands...))
    dp = [{} for _ in range(1 << n)]
    
    # Helper to generate a consistent sort key for uniqueness
    def get_sort_key(item):
        return str(item)

    # Initialize with single terms
    for i in range(n):
        val = terms[i]
        mask = (1 << i)
        dp[mask][val] = { ('NUM', val) }

    # Iterate through mask sizes
    for r in range(2, n + 1):
        for indices in itertools.combinations(range(n), r):
            mask = sum(1 << i for i in indices)
            set_bits = [b for b in range(n) if (mask >> b) & 1]
            
            # Split mask
            for k in range(1, r // 2 + 1):
                for sub_indices in itertools.combinations(set_bits, k):
                    s = sum(1 << i for i in sub_indices)
                    comp = mask - s # SageMath safe subtraction
                    
                    if k * 2 == r and s > comp: continue
                    if not dp[s] or not dp[comp]: continue
                    
                    # Combine results from submasks
                    for v1, exprs1 in dp[s].items():
                        for v2, exprs2 in dp[comp].items():
                            
                            for e1 in exprs1:
                                for e2 in exprs2:
                                    
                                    # --- ADDITION ---
                                    res_sum = v1 + v2
                                    if res_sum <= target:
                                        ops = []
                                        # Flatten left
                                        if e1[0] == 'SUM': ops.extend(e1[1])
                                        else: ops.append(e1)
                                        # Flatten right
                                        if e2[0] == 'SUM': ops.extend(e2[1])
                                        else: ops.append(e2)
                                        
                                        ops.sort(key=get_sort_key)
                                        new_struct = ('SUM', tuple(ops))
                                        
                                        if res_sum not in dp[mask]: dp[mask][res_sum] = set()
                                        dp[mask][res_sum].add(new_struct)
                                    
                                    # --- MULTIPLICATION ---
                                    # Skip *1 (Identity)
                                    if v1 == 1 or v2 == 1: continue
                                    
                                    res_prod = v1 * v2
                                    if res_prod <= target:
                                        ops = []
                                        # Flatten left
                                        if e1[0] == 'PROD': ops.extend(e1[1])
                                        else: ops.append(e1)
                                        # Flatten right
                                        if e2[0] == 'PROD': ops.extend(e2[1])
                                        else: ops.append(e2)
                                        
                                        ops.sort(key=get_sort_key)
                                        new_struct = ('PROD', tuple(ops))
                                        
                                        if res_prod not in dp[mask]: dp[mask][res_prod] = set()
                                        dp[mask][res_prod].add(new_struct)

    # --- Formatting Function for Cipher Output ---
    def format_cipher(expr):
        etype, content = expr
        
        if etype == 'NUM':
            # Return the Cipher Letter
            return term_map[content]
            
        elif etype == 'SUM':
            # Join with "+"
            return "+".join(format_cipher(c) for c in content)
            
        elif etype == 'PROD':
            parts = []
            for c in content:
                s = format_cipher(c)
                # Add brackets ONLY if the child is a SUM
                if c[0] == 'SUM':
                    s = f"({s})"
                parts.append(s)
            # Join with empty string (Implicit multiplication)
            return "".join(parts)

    # --- Collect and Print Solutions ---
    solutions = []
    # Check every mask for the target value
    for m in range(1 << n):
        if target in dp[m]:
            for struct in dp[m][target]:
                solutions.append(format_cipher(struct))
    
    if not solutions:
        return [f"No solution found for {target}."]
    
    # Sort by length for readability
    return sorted(list(set(solutions)), key=len)

# --- User Input Section ---
target_integer = 28020

# Run
results = solve_oeis_crypto_cipher(target_integer)

# Output
print(f"Cipher Results for {target_integer}:")
print(f"Key: A=1, B=2, C=4, D=11, E=25, F=64, G=171, H=569, I=3406, J=27697")
print("-" * 60)
for res in results:
    print(res)

No comments:

Post a Comment