Solution de ThierryBesancon pour This is fine

crypto

23 juillet 2026

On nous propose un programme PYTHON un peu inhabituel.

Ci joint une version simplifiée (j’ai simplement mis une seule lambda fonction dans L au lieu des 38 de l’énoncé) :

L = [
    lambda x: 7356954580121243762*x**16 - 67917758999022629485319994263285229323*x**15 - 126557346997785504703303593285520174611*x**14 - 79196433701250933379099644305803773692*x**13 + 64127295017451262308591178117921719607*x**12 + 30348988932379286893278017713168381811*x**11 + 103217349796193762180113460134492309958*x**10 - 154876828044950977759573152639253989872*x**9 - 83291919960546378198292499838313325081*x**8 + 13843350859630151992361239852646634059*x**7 - 102720501418550210355972956242885213268*x**6 - 155819885470062394096388278625509744351*x**5 - 71889517112932522335238158706394974633*x**4 - 102947773924158754256136745869287671436*x**3 - 123078785304424416159367972716706676890*x**2 + 52344605551728127581536635264341776866*x + 142567267056755772849168679088948045314,
]
try:
    flag = []
    for y in L:
        this = int(input(">>> "))
        fine = int(input(">>> "))
        assert this == fine
        this = y(this)
        fine = y(fine)
        assert this is fine
        flag.append(this | fine)
    print(bytes(flag).decode())
except:
    print("Nope!")

On nous demande assez bizarrement deux entrées « this » et « fine » qui doivent être égales (test assert avec l’opérateur d’égalité ==). Bon, a priori cela ne sert pas à grand chose. Sauf à attirer notre attention sur l’opérateur de comparaison.

Ensuite on calcule la valeur de la lambda fonction (ici chaque lambda fonction sera un polynôme de degré 16) pour « this » et « fine » ce qui en toute logique conduit à deux valeurs égales puisque les arguments sont finalement aussi égaux.

Mais le test du assert ne consiste pas en un test d’égalité mais en un test d’identicité via l’opérateur is. En PYTHON, cet opérateur renvoie true si deux variables font en fait référence à la même zone mémoire, au même objet. Par exemple le test est true ici :

a = [1, 2, 3]
b = a
assert a is b

En toute logique, il semble peu crédible ici que le calcul de la lambda fonction renvoie la même référence d’objet résultat pour deux calculs de suite.

Mais en lisant de la documentation sur le fonctionnement de l’opérateur is, on apprend que l’on pourra avoir une identicité si l’objet calculé est « court », cette définition de « court » étant assez dépendante de la version de PYTHON. Par contre, on semble s’accorder pour dire que si le calcul renvoie un « petit » entier alors on pourra avoir une identicité. Petit signifie ici souvent entre 0 et 256.

Cela tombe bien parce que le reste du programme fait :

flag = []
for y in L:
    ...
    this = y(this)
    fine = y(fine)
    assert this is fine
    flag.append(this | fine)
print(bytes(flag).decode())

On accumule donc les valeurs calculées qu’on convertira ensuite de leurs valeurs ASCII en caractères.

On peut donc affiner un peu plus les choses. On devra avoir une petite valeur entre 0x20 et 0x7d (classiquement les flags du FCSC sont constitués de caractères dans cet intervalle ASCII).

La partie this | fine est de l’intox pour nous impressionner car l’identicité fait qu’on OR deux valeurs identiques entre elles.

Résumons le problème :

Comme le challenge se résoud, qu’il se résoud dans ambiguité, on se doute que chaque caractère f du flag est tel que P(x) - f se factorise en un monôme de degré 1 de type X - a et d’un autre polynôme irréductible (donc sans racine entière) de degré 15.

Dit encore autrement, pour chaque polynôme de la liste L, on cherche donc les f permettant de rendre P(x) - f non irréductible.

D’où mon script de solution en PARI/GP (script complet ici - ci-dessous je donne une version abrégée):

L = [ \
  7356954580121243762*x^16 - 67917758999022629485319994263285229323*x^15 - 126557346997785504703303593285520174611*x^14 - 79196433701250933379099644305803773692*x^13 + 64127295017451262308591178117921719607*x^12 + 30348988932379286893278017713168381811*x^11 + 103217349796193762180113460134492309958*x^10 - 154876828044950977759573152639253989872*x^9 - 83291919960546378198292499838313325081*x^8 + 13843350859630151992361239852646634059*x^7 - 102720501418550210355972956242885213268*x^6 - 155819885470062394096388278625509744351*x^5 - 71889517112932522335238158706394974633*x^4 - 102947773924158754256136745869287671436*x^3 - 123078785304424416159367972716706676890*x^2 + 52344605551728127581536635264341776866*x + 142567267056755772849168679088948045314, \
...
] ;

foreach(L, l, \
  for(f = 0x20, 0x7d, \
    if( ! polisirreducible(l - f), \
      printf("%c", f); \
      break ; \
    ) \
  ) \
)

printf("\n") ;

quit ;

Je ne cherche pas à connaitre les entiers à entrer puisque la valeur qui nous intéresse est f.

L’exécution du script donne :

$ gp solve.gp
FCSC{dqcb7dVhWa9hunProTfJMsurwboPkT3V}

Bingo. Ce flag se valide.

QED.

🐒