在素域橢圓曲線運算過程當中,256位加法和減法運算結果經常位於區間[0,p)以外的情形,須要作+p或是-p的運算shell
256位NIST素域橢圓曲線參數p的生成公式爲:緩存
p = 2^256 − 2^224 + 2^192 + 2^96 − 1
按照符號將此式分解得:
函數
p = (2^256 + 2^192 + 2^96) - (2^224 + 1)
轉化爲16進制並按64位分節,變成下面的形式:優化
+: 0000000000000001 0000000000000000 0000000100000000 0000000000000000 -: 0000000100000000 0000000000000000 0000000000000000 0000000000000001 =: ffffffff00000001 0000000000000000 00000000ffffffff ffffffffffffffff
仔細觀察能夠發現,所涉及64位加法和減法中,只出現一個64位當即數:code
0000000100000000
假設某次256位減法最終發生借位,其低256位數值保存於寄存器r8:r11中,如今須要+p運算以修正之,如果用構成p的4個當即數直接運算的話,其代碼以下:編譯
# -------------- # r8:r11 += p256 # -------------- addq $0xffffffffffffffff, %r8 adcq $0xffffffff, %r9 adcq $0, %r10 adcq $0xffffffff00000001, %r11
由x64指令特性可知,這麼書寫是不容許的,大於32位的當即數會使編譯通不過,經過前面的分析可知,能夠將4個加法轉化爲3個加法和4個減法來實現,其代碼以下:class
movq $0x100000000, %rax addq %rax, %r9 adcq $0x0, %r10 adcq $0x1, %r11 # ---- subq $0x1, %r8 sbbq $0, %r9 sbbq $0, %r10 sbbq %rax, %r11
有沒有其它方法呢?固然有,好比能夠預先將素數p的4個64位數值保存於寄存器r12:r15中,其代碼以下:二進制
# -------------- # r12:r15 = p256 # r8:r11 += p256 # -------------- addq %r12, %r8 adcq %r13, %r9 adcq %r14, %r10 adcq %r15, %r11
爲了一個256位常數犧牲4個通用寄存器是萬不得已的選擇,除非此運算佔據總體運算的大部分,才值得這麼作,好比對素數p求乘法逆時,超過80%的運算都是+/-p,此時有必要將素數p直接保存在通用寄存器中以便隨時使用。
方法
利用x64當即數書寫規則,使用兩個寄存器RAX:RDX生成素數p的內容,其代碼以下:co
# ------------------------ # rax = 0x00000000ffffffff # rdx = 0xffffffff00000001 # ------------------------ movq $0xffffffff, %rax movq %rax, %rdx negq %rdx # -------------- # r8:r11 += p256 # -------------- addq $-1, %r8 adcq %rax, %r9 adcq $0, %r10 adcq %rdx, %r11
這裏特別要注意當即數-1的實際數值,在x86彙編裏至關於0xffffffff,即32個連續的二進制1,在x64彙編則是64個連續的二進制1,至關於0xffffffffffffffff,其它當即數的書寫規則和x86一致,都是32位有符號當即數,只有movq指令對rax操做時,才支持64位當即數,千萬要當心。
在編寫256位NIST素域橢圓曲線倍點函數時,最終採用的方案是使用兩個通用寄存器分別保存素數p的最高64位和最低64位,同時利用x64彙編的當即數書寫規則,其數值的生成代碼以下:
# ------------------------ # rbx = 0x00000000ffffffff # rbp = 0xffffffff00000001 # ------------------------ xorq %rbp, %rbp movq $0xffffffff, %rax movq %rax, %rbx subq %rax, %rbp
倍點函數內計算+p的代碼以下:
# --------------- # r12:r15 += p256 # --------------- addq $-1, %r12 adcq %rbx, %r13 adcq $0, %r14 adcq %rbp, %r15
倍點函數內計算-p的代碼以下:
# --------------- # r12:r15 -= p256 # --------------- subq $-1, %r12 sbbq %rbx, %r13 sbbq $0, %r14 sbbq %rbp, %r15
國密素域橢圓曲線SM2從公式上來說和NIST素域橢圓曲線有類似之處,一樣能夠優化+/-素數p的彙編代碼,首先咱們回顧一下國密SM2的素數p取值:
p256 = FFFFFFFEFFFFFFFF FFFFFFFFFFFFFFFF FFFFFFFF00000000 FFFFFFFFFFFFFFFF
現仍舊使用2個通用寄存器緩存素數p的部分數值,其數值生成代碼以下:
# ------------------------ # rbx = 0xFFFFFFFF00000000 # rbp = 0xFFFFFFFEFFFFFFFF # ------------------------ movq $-0x100000000, %rbx movq $-0x100000001, %rbp
SM2倍點函數內計算+p的代碼以下:
# -------------- # r8:r11 += p256 # -------------- addq $-1, %r8 adcq %rbx, %r9 adcq $-1, %r10 adcq %rbp, %r11
SM2倍點函數內計算-p的代碼以下:
# -------------- # r8:r11 -= p256 # -------------- subq $-1, %r8 sbbq %rbx, %r9 sbbq $-1, %r10 sbbq %rbp, %r11