# 知识点
- 二元非线性同余方程组
- Sage 的使用
- Sylvester 结式法解二元多次方程
# Sylvester 结式法
-
令、 分别数域 上的非常数多项式,且 的幂次为为, 的幂次为
-
定义 与 的 Sylvester 结式为一个矩阵
-
定义 和 的 Sylvester 行列式为 (Sylvester 结式),记作,这里的
-
定理:令、 分别数域 上的非常数多项式,则、 不互素当且仅当
# 解二元高次方程
令二元多次方程表示为
首先我们利用主元法,把 和 看做是 的多项式 和,因此这两个多项式不互素,于是利用 可以得到一个关于 的方程组,然后解这个方程组得到 的值,对于每个 的值,带入 或 求的 即可
# 题目
from Crypto.Util.number import bytes_to_long, getPrime | |
from secret import flag | |
l = len(flag) | |
assert l == 56 | |
x = bytes_to_long(flag[:l//2]) | |
y = bytes_to_long(flag[l//2:]) | |
p = getPrime(1024) | |
e = 0x10001 | |
x = pow(x, e, p) | |
y = pow(y, e, p) | |
a = (7 * x + x * y + 77 * y ** 7) % p | |
b = (x ** 7 + 777 * y) % p | |
print(f'p = {p}') | |
print(f'a = {a}') | |
print(f'b = {b}') | |
# p = 160676801612994301361202519503059426958636739446670462398261976532859847492256822690640058297338763725128097587993428329580105931247817467950370089691908132361316857330836120708767594061772979871315614755470773991633234068651435625372887767258609941208307491359777513843529144444836847722372845148836203335627 | |
# a = 30318995909014771647618268716833486449002423009996671727903532973647046764624121316716790986592523978549131384964872198795285872746623966910764159262479160147876027157581577141632378119375701270068263640642243000011932466519579133761464923463402462812787531220639360431295348786697861069940729757964584951972 | |
# b = 51036630170491152581994259808984114372634216659979376101433163181132141957563047348137651942358538069256102718534893846618166559129391336639526588292370462975735415885732360576961407017238385374280336346614960555565504032093702784952402038043052556719843691506943605133036720410419999467125928578673380637828 |
题意就是要我们在已知和下面同余方程组
求解 的值,然后已知 和下式
最终求解出 和
由于 是一个有限域,所以可以把所有操作看做是在有限域下进行的,用 Sage 可以自动在有限域下进行操作,考虑把同余方程组变形成数域 下的多项式
其中 和 分别是、 在 下的相反数
接下来是 Sage 脚本的编写
from sage.matrix.matrix2 import Matrix | |
def resultant(f1, f2, var): | |
return Matrix.determinant(f1.sylvester_matrix(f2, var)) #得到以 var 为变量的多项式 f1 和 f2 的 sylvester 结式的行列式 | |
p = 160676801612994301361202519503059426958636739446670462398261976532859847492256822690640058297338763725128097587993428329580105931247817467950370089691908132361316857330836120708767594061772979871315614755470773991633234068651435625372887767258609941208307491359777513843529144444836847722372845148836203335627 | |
a = 30318995909014771647618268716833486449002423009996671727903532973647046764624121316716790986592523978549131384964872198795285872746623966910764159262479160147876027157581577141632378119375701270068263640642243000011932466519579133761464923463402462812787531220639360431295348786697861069940729757964584951972 | |
b = 51036630170491152581994259808984114372634216659979376101433163181132141957563047348137651942358538069256102718534893846618166559129391336639526588292370462975735415885732360576961407017238385374280336346614960555565504032093702784952402038043052556719843691506943605133036720410419999467125928578673380637828 | |
e = 0x10001 | |
P.<x, y> = PolynomialRing(Zmod(p)) #定义模 p 下的多项式环,变量为 x 和 y | |
F = 7 * x + x * y + 77 * y ** 7 - a #F(x,y) | |
G = x ** 7 + 777 * y - b #G(x,y) | |
hx = resultant(F, G, y) #得到关于 res (x)=0 的多项式 | |
rx = hx.univariate_polynomial().roots() #得到 res (f,g)=0 的根,即 x 的所有取值 | |
#rx 中的每个元素一个二元组 | |
x, _ = zip(*rx) #获得所有二元组中的第一个元素 | |
#zip 的用法 | |
''' | |
a = ("John", "Charles", "Mike") | |
b = ("Jenny", "Christy", "Monica") | |
x = zip(a, b) | |
print(x): | |
(('John', 'Jenny'), ('Charles', 'Christy'), ('Mike', 'Monica')) | |
''' | |
y = [((b - i^7) * inverse_mod(777, p)) % p for i in x] #带回 x 得到 y | |
d = inverse_mod(e, p-1) | |
for i in range(len(x)): | |
m1 = pow(x[i], d, p) | |
m2 = pow(y[i], d, p) | |
print(long_to_bytes(m1)+long_to_bytes(m2)) |
得到、 后就变成了求解 了
最后会得到若干组解,其中
x=10473801139457439415841284907691978179887124828501791992501875324249
y=10027371126831070925652949180158084705794567689931733507098463327101
是合法的,最后的 flag
是 'ctfshow{1t_Is_S0o0o0o0o_3A5Y_70_50Lv3_m0duLaR_EqUAt10nS}
# 参考
CTF 七夕杯 WP