文中提到的论文是指 这个,论文中对Sylvester结式法做了简要的介绍
Sylvester结式法,结式,消元法,ctfshow 七夕杯 LUCK7,crypto,WriteUp
对于多变元方程组,求解的主要问题归结于消元问题,通过消元法去掉其中某些变元,使复杂方程组变成一个求解简单的单变元多项式方程。
现主要消元法有
吴方法
Grobner 基方法
迪克逊(Dixon)结式法
希儿维斯特(Sylvester)结式法
…
其中 Sylvester 结式法是一种经典的基本消元方法。
结式(Eliminant)
定义来自百度百科
指由两个多项式的系数所构成的一种行列式,或称Sylvester行列式
,结式可判断两个多项式是否有公根、是否互素,以及判断多项式是否有重根。
设
f ( x ) = a 0 x n + a 1 x n − 1 + . . . + a n g ( x ) = b 0 x m + b 1 x m − 1 + . . . + b m f(x)=a_0x^n+a_1x^{n-1}+...+a_n\\ g(x)=b_0x^m+b_1x^{m-1}+...+b_m f(x)=a0xn+a1xn−1+...+ang(x)=b0xm+b1xm−1+...+bm
将 f ( x ) f(x) f(x) 分别乘以 x x x ~ x m x^m xm,得到 m m m 个等式
同理,将 g ( x ) g(x) g(x) 分别乘以 x x x ~ x n x^n xn,得到 n n n 个等式
由此定义行列式 R ( f , g ) R(f,g) R(f,g)
R ( f , g ) = ∣ a 0 a 1 a 2 . . . . . . a n 0 . . . 0 0 a 0 a 1 . . . . . . a n − 1 a n . . . 0 0 0 a 0 . . . . . . a n − 2 a n − 1 . . . 0 ⋮ ⋮ ⋮ ⋮ ⋮ ⋮ ⋮ ⋮ ⋮ 0 0 . . . 0 a 0 . . . . . . . . . a n b 0 b 1 b 2 . . . . . . . . . b m . . . 0 0 b 0 b 1 . . . . . . . . . b m − 1 b m . . . ⋮ ⋮ ⋮ ⋮ ⋮ ⋮ ⋮ ⋮ ⋮ 0 . . . 0 b 0 b 1 . . . . . . . . . b m ∣ R(f,g)=\left| \begin{matrix} a_0 & a_1 & a_2 & ... & ... & a_n & 0 & ... & 0\\ 0 & a_0 & a_1 & ... & ... & a_{n-1} & a_n & ... & 0\\ 0 & 0 & a_0 & ... & ... & a_{n-2} & a_{n-1} & ... & 0\\ \vdots & \vdots & \vdots & \vdots & \vdots & \vdots & \vdots & \vdots & \vdots\\ 0 & 0 & ... & 0 & a_0 & ... & ... & ... & a_n\\ b_0 & b_1 & b_2 & ... & ... & ... & b_m & ... & 0\\ 0 & b_0 & b_1 & ... & ... & ... & b_{m-1} & b_m & ...\\ \vdots & \vdots & \vdots & \vdots & \vdots & \vdots & \vdots & \vdots & \vdots\\ 0 & ... & 0 & b_0 & b_1 & ... & ... & ... & b_m \end{matrix} \right| R(f,g)=∣
∣a000⋮0b00⋮0a1a00⋮0b1b0⋮...a2a1a0⋮...b2b1⋮0.........⋮0......⋮b0.........⋮a0......⋮b1anan−1an−2⋮.........⋮...0anan−1⋮...bmbm−1⋮............⋮......bm⋮...000⋮an0...⋮bm∣
∣
R ( f , g ) R(f,g) R(f,g) 为 f f f 和 g g g 的结式
相关定理
- (在复数域中)多项式 f f f 和 g g g 有公共根的充要条件是它们的结式 R ( f , g ) = 0 R(f,g)=0 R(f,g)=0
- 多项式 f f f 和 g g g 互素的充要条件是它们的结式 R ( f , g ) ≠ 0 R(f,g)\not=0 R(f,g)=0
Sylvester 结式法消元
设二元方程
f ( x , y ) = a n ( y ) x n + a n − 1 ( y ) x n − 2 + a n − 2 x n − 2 + . . . + a 0 ( y ) g ( x , y ) = b n ( y ) x m + b m − 1 ( y ) x m − 2 + b m − 2 x m − 2 + . . . + b 0 ( y ) f(x,y)=a_n(y)x^n+a_{n-1}(y)x^{n-2}+a_{n-2}x^{n-2}+...+a_0(y)\\ g(x,y)=b_n(y)x^m+b_{m-1}(y)x^{m-2}+b_{m-2}x^{m-2}+...+b_0(y)\\ f(x,y)=an(y)xn+an−1(y)xn−2+an−2xn−2+...+a0(y)g(x,y)=bn(y)xm+bm−1(y)xm−2+bm−2xm−2+...+b0(y)
其中, a i ( y ) , b j ( y ) a_i(y),b_j(y) ai(y),bj(y) 可以看作是 f ( x , y ) , g ( x , y ) f(x,y),g(x,y) f(x,y),g(x,y) 中 x i , x j x^i,x^j xi,xj 的系数
利用上诉方法求出 Sylvester 结式,这样将求解方程组公共零点解,转化为对其求解 Sylvester 结式,并使结式 R ( f , g ) = 0 R(f,g)=0 R(f,g)=0
于是通过利用求解结式的方法,消去了变量 x x x(或者变元 y y y),将复杂多项式方程简化为求解单一变元多项式的根。
这就是 Sylvester 结式法消元的原理
实现
论文中对实现流程的描述
此处我使用 sageMath 集成的函数来实现
尝试求解以下方程组的零解
f ( x , y ) = x 3 − 2 x 2 y + 4 x y − y 2 − 2 g ( x , y ) = 2 x y 2 + x y − y 3 − 2 \begin{array}{l} f(x,y)=x^3 - 2x^2y + 4xy - y^2 - 2\\ g(x,y)=2xy^2 + xy - y^3 - 2 \end{array} f(x,y)=x3−2x2y+4xy−y2−2g(x,y)=2xy2+xy−y3−2
对这个方程组
from sage.matrix.matrix2 import Matrix
P.<x,y> = PolynomialRing(ZZ)
f = x^3 - 2*x^2*y + 4*x*y - y^2 - 2
g = 2*x*y^2 + x*y - y^3 - 2
syl_x = f.sylvester_matrix(g,x)
syl_y = f.sylvester_matrix(g,y)
# 分别是通过代入,消去 x 和 y
print(syl_x)
print(syl_y)
det = Matrix.determinant(syl_x)
# 化为单变元,直接求解
# 如果最开始是二元函数的话,消掉一个元就已经是单变元函数了,但还是需要执行这一步
r = det.univariate_polynomial()
rr = r.roots()
print(rr)
# [(1,1)]
代表 y y y 有两个相同的解,即 1
将 y = 1 y=1 y=1 代回等式 f f f ,再求解,得到 x x x 的值
ctfshow 2022 七夕杯 Luck7
题目
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 = 65537 #e = '0x10001' print(int(e,16))
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
脚本
有官方WP,此方法也是通过官方WP才知道的。
使用 Sylvester 结式法直接解即可
# Sage
from sage.matrix.matrix2 import Matrix
from Crypto.Util.number import long_to_bytes
def resultant(f1, f2, var):
return Matrix.determinant(f1.sylvester_matrix(f2, var))
p = 160676801612994301361202519503059426958636739446670462398261976532859847492256822690640058297338763725128097587993428329580105931247817467950370089691908132361316857330836120708767594061772979871315614755470773991633234068651435625372887767258609941208307491359777513843529144444836847722372845148836203335627
a = 30318995909014771647618268716833486449002423009996671727903532973647046764624121316716790986592523978549131384964872198795285872746623966910764159262479160147876027157581577141632378119375701270068263640642243000011932466519579133761464923463402462812787531220639360431295348786697861069940729757964584951972
b = 51036630170491152581994259808984114372634216659979376101433163181132141957563047348137651942358538069256102718534893846618166559129391336639526588292370462975735415885732360576961407017238385374280336346614960555565504032093702784952402038043052556719843691506943605133036720410419999467125928578673380637828
e = 0x10001
P.<x, y> = PolynomialRing(Zmod(p))
f1 = 7 * x + x * y + 77 * y ** 7 - a
f2 = x ** 7 + 777 * y - b
hx = resultant(f1, f2, y)
rx = hx.univariate_polynomial().roots()
x, _ = zip(*rx)
y = [((b - i^7) * inverse_mod(777, p)) % p for i in x]
d = inverse_mod(e, p-1)
for i in range(len(x)):
m1 = pow(x[i], d, p)a
m2 = pow(y[i], d, p)
try:
print(bytes.fromhex(hex(m1)[2:]).decode(),end='')
print(bytes.fromhex(hex(m2)[2:]).decode())
except:
pass