6
社区成员
发帖
与我相关
我的任务
分享有两种“数学”计算——数值计算和符号计算。
数值型(如 Octave、Julia、NumPy 等)采用大量数字(通常是它们的整个向量和矩阵),并进行一些数值计算。
符号式(如 Z3、SageMath)采用抽象数学表达式,并对它们进行转换。在实践中,大多数系统都有些混合,但这仍然是一个有用的区别。
SageMath 是一种相当奇怪的语言,因为它 99% 是 Python,并且在 Python 引擎上运行,但它并不完全是 Python,他们引入了一堆“预解析”更改以使其对数学更加友好。这有点像 React 的 JSX 或 Babel 与普通 JavaScript 之间的关系。
没有必要为 Hello World、FizzBuzzes 等烦恼,因为您可以在 SageMath 上运行 Python 代码,并且它们通常会正常工作,除非您碰巧遇到其中一个差异。
您最常从 Jupyter Notebook 或类似设备运行 SageMath,但也可以从命令行运行它。
两个最明显的语法差异是/和^,但即使是普通数字也不完全相同:
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-comment-color)">#!/usr/bin/env sage
</span>
<span style="color:var(--syntax-comment-color)"># XOR in Python, ** in SageMath
</span><span style="color:var(--syntax-declaration-color)">print</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-literal-color)">3</span><span style="color:var(--syntax-error-color)">^</span><span style="color:var(--syntax-literal-color)">4</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-comment-color)"># Floats in Python, Rationals in SageMath
</span><span style="color:var(--syntax-declaration-color)">print</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-literal-color)">2</span><span style="color:var(--syntax-error-color)">/</span><span style="color:var(--syntax-literal-color)">3</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-comment-color)"># All numbers are wrapped in special classes
</span><span style="color:var(--syntax-declaration-color)">print</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">type</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-literal-color)">2</span><span style="color:var(--syntax-text-color)">))</span>
<span style="color:var(--syntax-declaration-color)">print</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">type</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-literal-color)">2</span><span style="color:var(--syntax-error-color)">/</span><span style="color:var(--syntax-literal-color)">3</span><span style="color:var(--syntax-text-color)">))</span>
</code></span></span>
让我们尝试运行它:
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code>$ sage syntax.sage
81
2/3
<class 'sage.rings.integer.Integer'>
<class 'sage.rings.rational.Rational'>
$ python3 syntax.sage
7
0.6666666666666666
<class 'int'>
<class 'float'>
</code></span></span>
但我们甚至可以看到 Sage 将代码转换成什么(我稍微调整了间距):
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-comment-color)"># This file was *autogenerated* from the file syntax.sage
</span><span style="color:var(--syntax-error-color)">from</span> <span style="color:var(--syntax-text-color)">sage.all_cmdline</span> <span style="color:var(--syntax-error-color)">import</span> <span style="color:var(--syntax-error-color)">*</span> <span style="color:var(--syntax-comment-color)"># import sage library
</span>
<span style="color:var(--syntax-text-color)">_sage_const_3</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">Integer</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-literal-color)">3</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-text-color)">_sage_const_4</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">Integer</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-literal-color)">4</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-text-color)">_sage_const_2</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">Integer</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-literal-color)">2</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-comment-color)">#!/usr/bin/env sage
</span>
<span style="color:var(--syntax-comment-color)"># XOR in Python, ** in SageMath
</span><span style="color:var(--syntax-declaration-color)">print</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">_sage_const_3</span> <span style="color:var(--syntax-error-color)">**</span> <span style="color:var(--syntax-text-color)">_sage_const_4</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-comment-color)"># Floats in Python, Rationals in SageMath
</span><span style="color:var(--syntax-declaration-color)">print</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">_sage_const_2</span> <span style="color:var(--syntax-error-color)">/</span> <span style="color:var(--syntax-text-color)">_sage_const_3</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-comment-color)"># All numbers are wrapped in special classes
</span><span style="color:var(--syntax-declaration-color)">print</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">type</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">_sage_const_2</span><span style="color:var(--syntax-text-color)">))</span>
<span style="color:var(--syntax-declaration-color)">print</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">type</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">_sage_const_2</span> <span style="color:var(--syntax-error-color)">/</span> <span style="color:var(--syntax-text-color)">_sage_const_3</span><span style="color:var(--syntax-text-color)">))</span>
</code></span></span>
让我们从一些高中的东西开始,比如限制:
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-comment-color)">#!/usr/bin/env sage
</span>
<span style="color:var(--syntax-declaration-color)">print</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"limit of sin(x) / x as x approaches 0"</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-declaration-color)">print</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">limit</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">sin</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">x</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-error-color)">/</span> <span style="color:var(--syntax-text-color)">x</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">x</span><span style="color:var(--syntax-error-color)">=</span><span style="color:var(--syntax-literal-color)">0</span><span style="color:var(--syntax-text-color)">))</span>
<span style="color:var(--syntax-declaration-color)">print</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"limit of sin(x) / x as x approaches infinity"</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-declaration-color)">print</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">limit</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">sin</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">x</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-error-color)">/</span> <span style="color:var(--syntax-text-color)">x</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">x</span><span style="color:var(--syntax-error-color)">=</span><span style="color:var(--syntax-text-color)">oo</span><span style="color:var(--syntax-text-color)">))</span>
<span style="color:var(--syntax-declaration-color)">print</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"limit of (1+1/x)^x as x approaches infinity"</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-declaration-color)">print</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">limit</span><span style="color:var(--syntax-text-color)">((</span><span style="color:var(--syntax-literal-color)">1</span><span style="color:var(--syntax-error-color)">+</span><span style="color:var(--syntax-literal-color)">1</span><span style="color:var(--syntax-error-color)">/</span><span style="color:var(--syntax-text-color)">x</span><span style="color:var(--syntax-text-color)">)</span><span style="color:var(--syntax-error-color)">^</span><span style="color:var(--syntax-text-color)">x</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">x</span><span style="color:var(--syntax-error-color)">=</span><span style="color:var(--syntax-text-color)">oo</span><span style="color:var(--syntax-text-color)">))</span>
</code></span></span>
当我们运行它时:
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code>$ ./limits.sage
limit of sin(x) / x as x approaches 0
1
limit of sin(x) / x as x approaches infinity
0
limit of (1+1/x)^x as x approaches infinity
e
</code></span></span>
在 sage 中,很多数学符号都是预先定义的。x, sin,oo都是符号性的,而不是您在普通 Python 中所期望的。
Infinity 的别名oo只是两个os,而不是 Unicode 无限字符。这可能是为了便于输入,但有点烦人的是 Python 不支持变量名中的 ∞,因为它在技术上不是一个“字母”。Raku 具有开箱即用的 ∞,而 Julia 默认情况下没有,但您可以∞ = inf在 Julia 中做到。
我们可以做一些简单的区分:
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-comment-color)">#!/usr/bin/env sage
</span>
<span style="color:var(--syntax-declaration-color)">print</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"diff of (x+2)*(x-2):"</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-declaration-color)">print</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">diff</span><span style="color:var(--syntax-text-color)">((</span><span style="color:var(--syntax-text-color)">x</span><span style="color:var(--syntax-error-color)">+</span><span style="color:var(--syntax-literal-color)">2</span><span style="color:var(--syntax-text-color)">)</span><span style="color:var(--syntax-error-color)">*</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">x</span><span style="color:var(--syntax-error-color)">-</span><span style="color:var(--syntax-literal-color)">2</span><span style="color:var(--syntax-text-color)">),</span> <span style="color:var(--syntax-text-color)">x</span><span style="color:var(--syntax-text-color)">))</span>
<span style="color:var(--syntax-declaration-color)">print</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"diff of cos(x^3) / x^3:"</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-declaration-color)">print</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">diff</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">cos</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">x</span><span style="color:var(--syntax-error-color)">^</span><span style="color:var(--syntax-literal-color)">3</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-error-color)">/</span> <span style="color:var(--syntax-text-color)">x</span><span style="color:var(--syntax-error-color)">^</span><span style="color:var(--syntax-literal-color)">3</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">x</span><span style="color:var(--syntax-text-color)">))</span>
</code></span></span>
哪个输出:
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code>./diff.sage
diff of (x+2)*(x-2):
2*x
diff of cos(x^3) / x^3:
-3*sin(x^3)/x - 3*cos(x^3)/x^4
</code></span></span>
当然还有整合。我们还可以得到数值近似。Sage 采用二进制而不是十进制数字要求的精度。
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-comment-color)">#!/usr/bin/env sage
</span>
<span style="color:var(--syntax-text-color)">f</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-literal-color)">1</span><span style="color:var(--syntax-error-color)">/</span><span style="color:var(--syntax-text-color)">x</span>
<span style="color:var(--syntax-declaration-color)">print</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"Integral of f(x) = 1/x from 5 to 10:"</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-declaration-color)">print</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">f</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">integral</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">x</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-literal-color)">5</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-literal-color)">10</span><span style="color:var(--syntax-text-color)">))</span>
<span style="color:var(--syntax-declaration-color)">print</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"Numerical approximation to 100 binary digits:"</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-declaration-color)">print</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">f</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">integral</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">x</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-literal-color)">5</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-literal-color)">10</span><span style="color:var(--syntax-text-color)">).</span><span style="color:var(--syntax-text-color)">n</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-literal-color)">100</span><span style="color:var(--syntax-text-color)">))</span>
</code></span></span>
哪个输出:
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code>$ ./integral.sage
Integral of f(x) = 1/x from 5 to 10:
log(10) - log(5)
Numerical approximation to 100 binary digits:
0.69314718055994530941723212146
</code></span></span>
SageMath 可以很好地对实数或复数进行所有数学运算,但许多其他系统也可以。
SageMath 的独特之处在于它在离散数学方面的优势,这对于密码学或 CTF 来说非常重要。
让我们从 GF(p)(也称为 Zp 和其他一些东西)字段的最简单的示例开始 - 基本上是整数模 p,因此当您对它们进行加、减或乘时,它们会环绕:
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-comment-color)">#!/usr/bin/env sage
</span>
<span style="color:var(--syntax-text-color)">p</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-literal-color)">65537</span>
<span style="color:var(--syntax-text-color)">F</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">GF</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">p</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-declaration-color)">print</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"Some addition in GF(65537):"</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-declaration-color)">for</span> <span style="color:var(--syntax-text-color)">i</span> <span style="color:var(--syntax-error-color)">in</span> <span style="color:var(--syntax-text-color)">range</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-literal-color)">10</span><span style="color:var(--syntax-text-color)">):</span>
<span style="color:var(--syntax-text-color)">a</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">F</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">random_element</span><span style="color:var(--syntax-text-color)">()</span>
<span style="color:var(--syntax-text-color)">b</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">F</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">random_element</span><span style="color:var(--syntax-text-color)">()</span>
<span style="color:var(--syntax-declaration-color)">print</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">f</span><span style="color:var(--syntax-string-color)">"</span><span style="color:var(--syntax-string-color)">{</span><span style="color:var(--syntax-text-color)">a</span><span style="color:var(--syntax-string-color)">}</span><span style="color:var(--syntax-string-color)"> + </span><span style="color:var(--syntax-string-color)">{</span><span style="color:var(--syntax-text-color)">b</span><span style="color:var(--syntax-string-color)">}</span><span style="color:var(--syntax-string-color)"> = </span><span style="color:var(--syntax-string-color)">{</span><span style="color:var(--syntax-text-color)">a</span> <span style="color:var(--syntax-error-color)">+</span> <span style="color:var(--syntax-text-color)">b</span><span style="color:var(--syntax-string-color)">}</span><span style="color:var(--syntax-string-color)">"</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-declaration-color)">print</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"Some inverses in GF(65537):"</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-declaration-color)">for</span> <span style="color:var(--syntax-text-color)">i</span> <span style="color:var(--syntax-error-color)">in</span> <span style="color:var(--syntax-text-color)">range</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-literal-color)">10</span><span style="color:var(--syntax-text-color)">):</span>
<span style="color:var(--syntax-text-color)">a</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">F</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">random_element</span><span style="color:var(--syntax-text-color)">()</span>
<span style="color:var(--syntax-text-color)">b</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">a</span><span style="color:var(--syntax-error-color)">^-</span><span style="color:var(--syntax-literal-color)">1</span>
<span style="color:var(--syntax-declaration-color)">print</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">f</span><span style="color:var(--syntax-string-color)">"</span><span style="color:var(--syntax-string-color)">{</span><span style="color:var(--syntax-text-color)">a</span><span style="color:var(--syntax-string-color)">}</span><span style="color:var(--syntax-string-color)"> * </span><span style="color:var(--syntax-string-color)">{</span><span style="color:var(--syntax-text-color)">b</span><span style="color:var(--syntax-string-color)">}</span><span style="color:var(--syntax-string-color)"> = </span><span style="color:var(--syntax-string-color)">{</span><span style="color:var(--syntax-text-color)">a</span> <span style="color:var(--syntax-error-color)">*</span> <span style="color:var(--syntax-text-color)">b</span><span style="color:var(--syntax-string-color)">}</span><span style="color:var(--syntax-string-color)">"</span><span style="color:var(--syntax-text-color)">)</span>
</code></span></span>
其中随机输出:
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code>./zp.sage
Some addition in GF(65537):
5993 + 52077 = 58070
34573 + 35447 = 4483
64465 + 9539 = 8467
23830 + 64214 = 22507
33632 + 5984 = 39616
32744 + 55138 = 22345
7174 + 12223 = 19397
12815 + 49721 = 62536
21107 + 51922 = 7492
32436 + 21708 = 54144
Some inverses in GF(65537):
4454 * 21880 = 1
8250 * 31990 = 1
2139 * 17403 = 1
34523 * 59411 = 1
44260 * 56663 = 1
3474 * 34655 = 1
53770 * 11490 = 1
12588 * 61575 = 1
34995 * 24902 = 1
2534 * 14354 = 1
</code></span></span>
GF(p) 加法和乘法是几乎所有编程语言都可以处理的领域,因为这只是对 p 进行模运算。
像 GF(p) 除法、逆运算等等——通常不是现成的。
SageMath 可以处理比 GF(p) 域复杂得多的数学结构。其中一种值得注意的结构是椭圆曲线,它是现代密码学的基本构建块之一。
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-comment-color)">#!/usr/bin/env sage
</span>
<span style="color:var(--syntax-text-color)">F</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">GF</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-literal-color)">101</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-text-color)">EC</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">EllipticCurve</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">F</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">[</span><span style="color:var(--syntax-literal-color)">2</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-literal-color)">3</span><span style="color:var(--syntax-text-color)">])</span>
<span style="color:var(--syntax-declaration-color)">for</span> <span style="color:var(--syntax-text-color)">i</span> <span style="color:var(--syntax-error-color)">in</span> <span style="color:var(--syntax-text-color)">range</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-literal-color)">10</span><span style="color:var(--syntax-text-color)">):</span>
<span style="color:var(--syntax-text-color)">a</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">EC</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">random_element</span><span style="color:var(--syntax-text-color)">()</span>
<span style="color:var(--syntax-text-color)">b</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">EC</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-text-color)">random_element</span><span style="color:var(--syntax-text-color)">()</span>
<span style="color:var(--syntax-declaration-color)">print</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">f</span><span style="color:var(--syntax-string-color)">"</span><span style="color:var(--syntax-string-color)">{</span><span style="color:var(--syntax-text-color)">a</span><span style="color:var(--syntax-string-color)">}</span><span style="color:var(--syntax-string-color)"> + </span><span style="color:var(--syntax-string-color)">{</span><span style="color:var(--syntax-text-color)">b</span><span style="color:var(--syntax-string-color)">}</span><span style="color:var(--syntax-string-color)"> = </span><span style="color:var(--syntax-string-color)">{</span><span style="color:var(--syntax-text-color)">a</span> <span style="color:var(--syntax-error-color)">+</span> <span style="color:var(--syntax-text-color)">b</span><span style="color:var(--syntax-string-color)">}</span><span style="color:var(--syntax-string-color)">"</span><span style="color:var(--syntax-text-color)">)</span>
</code></span></span>
哪个输出:
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code>./ecc.sage
(84 : 56 : 1) + (41 : 15 : 1) = (40 : 94 : 1)
(41 : 15 : 1) + (50 : 41 : 1) = (57 : 51 : 1)
(0 : 1 : 0) + (90 : 93 : 1) = (90 : 93 : 1)
(27 : 67 : 1) + (56 : 30 : 1) = (35 : 86 : 1)
(50 : 41 : 1) + (11 : 89 : 1) = (20 : 93 : 1)
(30 : 55 : 1) + (30 : 55 : 1) = (35 : 15 : 1)
(9 : 12 : 1) + (92 : 93 : 1) = (96 : 26 : 1)
(49 : 40 : 1) + (40 : 94 : 1) = (48 : 55 : 1)
(81 : 89 : 1) + (35 : 15 : 1) = (21 : 69 : 1)
(99 : 71 : 1) + (0 : 1 : 0) = (99 : 71 : 1)
</code></span></span>
我主要使用 SageMath 进行 CTF,这个示例改编自此类挑战之一,但数字有所改变。
这是一个两步攻击,但第一部分发生在挑战的背景故事中。
第一步是我们破解了 Alice 和 Bob 之间的参数协商,让他们认为对方只支持使用 90 年代的“导出级”加密和非常短的密钥,这种加密足以抵御随意的攻击者,但实际上并非如此反对国家安全局等。感谢 SageMath,我们可以做到 NSA 在 90 年代可以做到的事情,并破解此类相对较短的密钥。
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-comment-color)">#!/usr/bin/env sage
</span>
<span style="color:var(--syntax-comment-color)"># "Export Grade" Diffie-Hellman Key Exchange
</span><span style="color:var(--syntax-text-color)">K</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">GF</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-literal-color)">57702167561280060733</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-text-color)">g</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">K</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-literal-color)">2</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-comment-color)"># We don't know these numbers, CTF server does
</span><span style="color:var(--syntax-text-color)">secret_a</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-literal-color)">21994334292003664313</span>
<span style="color:var(--syntax-text-color)">secret_b</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-literal-color)">5307079022839176516</span>
<span style="color:var(--syntax-comment-color)"># What we get from the challenge is these:
# Alice sent to Bob: g^a
# Bob sent to Alice: g^a
</span><span style="color:var(--syntax-text-color)">ga</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">K</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-literal-color)">20214349094702392183</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-text-color)">gb</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">K</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-literal-color)">36652172046887073403</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-comment-color)"># This is fast only because SageMath knows all the fancy algorithms
# It would be completely non-viable to brute force
# and extremely tedious and slow to code yourself:
</span><span style="color:var(--syntax-text-color)">a</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">discrete_log</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">ga</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">g</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-text-color)">gab</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-text-color)">gb</span> <span style="color:var(--syntax-error-color)">^</span> <span style="color:var(--syntax-text-color)">a</span>
<span style="color:var(--syntax-declaration-color)">print</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">f</span><span style="color:var(--syntax-string-color)">"We hacked the key: </span><span style="color:var(--syntax-string-color)">{</span><span style="color:var(--syntax-text-color)">gab</span><span style="color:var(--syntax-string-color)">}</span><span style="color:var(--syntax-string-color)">"</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-comment-color)"># CTF server can verify our solution:
</span><span style="color:var(--syntax-declaration-color)">print</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">f</span><span style="color:var(--syntax-string-color)">"Alice shared key: </span><span style="color:var(--syntax-string-color)">{</span><span style="color:var(--syntax-text-color)">gb</span><span style="color:var(--syntax-error-color)">^</span><span style="color:var(--syntax-text-color)">secret_a</span><span style="color:var(--syntax-string-color)">}</span><span style="color:var(--syntax-string-color)">"</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-declaration-color)">print</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">f</span><span style="color:var(--syntax-string-color)">"Bob shared key: </span><span style="color:var(--syntax-string-color)">{</span><span style="color:var(--syntax-text-color)">ga</span><span style="color:var(--syntax-error-color)">^</span><span style="color:var(--syntax-text-color)">secret_b</span><span style="color:var(--syntax-string-color)">}</span><span style="color:var(--syntax-string-color)">"</span><span style="color:var(--syntax-text-color)">)</span>
</code></span></span>
哪个输出:
<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code>$ ./mitm.sage
We hacked the key: 44661687795688390997
Alice shared key: 44661687795688390997
Bob shared key: 44661687795688390997
</code></span></span>
您已经了解其语法,因为它 99% 都是 Python,因此它的学习曲线非常友好。
对于数值数学来说,有很多替代方案,包括很多基于 Python 的解决方案,我不认为 SageMath 所做的有那么特别。
对于符号数学,尤其是任何与密码学相关的数学,它真的很好,而且我认为没有其他东西真正与其功能相匹配。
有一些纯 Python 符号数学库,例如SymPy,但乍一看它们似乎缺乏大部分离散数学和加密功能。当然,这需要权衡——使用 100% Python 并放弃 SageMath 预解析意味着在某些情况下代码会更加冗长。
总的来说,SageMath 对于任何对 CTF 感兴趣或了解现代密码学和加密货币如何工作的人来说都是一个有用的工具。在这个有限的利基市场中,这确实令人惊叹。
如果您对密码学不感兴趣,并且只有常规的数学需求,SageMath 可以为您工作,但您通常可以坚持使用常用的 Python 库(如 NumPy 和 Pandas),或使用数值数学语言(如 Julia)。