當前位置:首頁 » 操作系統 » 蒙哥馬利演算法

蒙哥馬利演算法

發布時間: 2022-08-12 15:44:28

『壹』 蒙哥馬利約減

資料上說:
「模乘過程中復雜度最高的環節是求模運算,因為一次除法實際上包含了多次加法、減法和乘法,如果在演算法中能夠盡量減少除法甚至避免除法,則演算法的效率會大大提高。「
「我們最終實現了不含除法的模冪演算法,這就是著名的蒙哥馬利演算法」

速冪運算的好處是減少了運算量,極大地提高了速度。例如A^65525(A的65535次冪),原始演算法要做65535-1=65534次乘法,而快速冪運算只需要做(16-1)×2=30次乘法。

原理其實很好懂,假設要計算A^B,即底數是A,指數是B。把B寫成二進制形式,拿4位來舉例:B=b4b3b2b1(二進制)。
先用B=1111(二進制)來做解釋。顯然A^B = A × A^2 × A^4 × A^8。
又顯然,
A^2 = A × A,
A^4 = A^2 × A^2,
A^8 = A^4 × A^4。
假如B的二進制位數更多,則依此類推。
上面這段看懂了嗎?如果看懂的,就應該能夠寫出B=1111(二進制)情況下,A^B的快速冪運算程序。

『貳』 RSA里的mod計算問題

RSA軟體演算法以及硬體實現都是利用蒙哥馬利模乘實現你的要求的
由於RSA
的核心演算法是模冪運算,模冪運算又相當於模乘運算的循環,要提高
RSA
演算法的效率,首要問題在於提高模乘運算的效率。不難發現,模乘過程中復雜
度最高的環節是求模運算,因為一次除法實際上包含了多次加法、減法和乘法,如
果在演算法中能夠盡量減少除法甚至避免除法,則演算法的效率會大大提高。
設A=Sum[i=0
to
k](A*2**i),0<=A<=1,則:
C=
A*B
=
Sum[i=0
to
k](A*B*2**i)
可用循環處理為:
C=0
FOR
i
FROM
k
TO
0
C=C*2
C=C+A*B
RETURN
C
若令
C'=
A*B*2**(-k),則:
C'=
Sum[i=0
to
k](A*B*2**(i-k))
用循環處理即:
C'=0
FOR
i
FROM
0
TO
k
C'=C'+A*B
C'=C'/2
RETURN
C'
通過這一演算法求A*B*2**(-k)是不精確的,因為在循環中每次除以2都可能有餘
數被舍棄了,但是可以通過這一演算法求A*B*2**(-k)
%N的精確值,方法是在對C'除
2之前,讓C'加上C'[0]*N。由於在RSA中N是兩個素數的積,總是奇數,所以當C'是
奇數時,C'[0]=1,C'+C'[0]*N
就是偶數,而當C'為偶數時C'[0]=0,C'+C'[0]*N
還是偶數,這樣C'/2
就不會有餘數被舍棄。又因為C'+N
%N
=
C'
%N,所以在計算
過程中加若干次N,並不會影響結果的正確性。可以將演算法整理如下:
C'=0
FOR
i
FROM
0
TO
k
C'=C'+A*B
C'=C'+C'[0]*N
C'=C'/2
IF
C'>=N
C'=C'-N
RETURN
C'
由於在RSA中A、B總是小於N,又0<=A,C'[0]<=1,所以:
C'
=
(C'+A*B+C'[0]*N)/2
C'
<
(C'+2N)/2
2C'
<
C'+2N
C'
<
2N
既然C'總是小於2N,所以求C'
%N
就可以很簡單地在結束循環後用一次減法來
完成,即在求A*B*2**(-k)
%N的過程中不用反復求模,達到了我們避免做除法的目
的。當然,這一演算法求得的是A*B*2**(-k)
%N,而不是我們最初需要的A*B
%N。但
是利用A*B*2**(-k)我們同樣可以求得A**E
%N。
設R=2**k
%N,R'=2**(-k)
%N,E=Sum[i=0
to
n](E*2**i):
A'=A*R
%N
X=A'
FOR
i
FROM
n
TO
0
X=X*X*R'
%N
IF
E=1
X=X*A'*R'
%N
X=X*1*R'
%N
RETURN
X
最初:
X
=
A*R
%N,
開始循環時:
X
=
X*X*R'
%N
=
A*R*A*R*R'
%N
=
A**2*R
%N
反復循環之後:
X
=
A**E*R
%N
最後:
X
=
X*1*R'
%N
=
A**E*R*R'
%N
=
A**E
%N
如此,我們最終實現了不含除法的模冪演算法,這就是著名的蒙哥馬利演算法,而
X*Y*R'
%N
則被稱為「蒙哥馬利模乘」。以上討論的是蒙哥馬利模乘最簡單,最容
易理解的二進制形式。蒙哥馬利演算法的核心思想在於將求A*B
%N轉化為不需要反復
取模的A*B*R'
%N,但是利用二進制演算法求1024位的A*B*R'
%N,需要循環1024次之
多,我么必然希望找到更有效的計算A*B*R'
%N的演算法。
考慮將A表示為任意的r進制:
A
=
Sum[i=0
to
k](A*r**i)
0<=A<=r
我們需要得到的蒙哥馬利乘積為:
C'=
A*B*R'
%N
R'=r**(-k)
則以下演算法只能得到C'的近似值
C'=0
FOR
i
FROM
0
TO
k
C'=C'+A*B
C'=C'/r
IF
C'>=N
C'=C'-N
RETURN
C'
因為在循環中每次C'=C'/r
時,都可能有餘數被舍棄。假如我們能夠找到一個
系數
q,使得(C'
+
A*B
+
q*N)
%r
=0,並將演算法修改為:
C'=0
FOR
i
FROM
0
TO
k
C'=C'+A*B+q*N
C'=C'/r
IF
C'>=N
C'=C'-N
RETURN
C'
則C'的最終返回值就是A*B*R'
%N的精確值,所以關鍵在於求q。由於:
(C'
+
A*B
+
q*N)
%r
=0
==>
(C'
%r
+
A*B
%r
+
q*N
%r)
%r
=0
==>
(C'[0]
+
A*B[0]
+
q*N[0])
%r
=0
若令N[0]*N[0]'
%r
=1,q=(C'[0]+A*B[0])*(r-N[0]')
%r,則:
(C'[0]
+
A*B[0]
+
q*N[0])
%r
=
(C'[0]+A*B[0]
-
(C'[0]+A*B[0])*N[0]'*N[0])
%r)
%r
=
0
於是我們可以得出r為任何值的蒙哥馬利演算法:
m=r-N[0]'
C'=0
FOR
i
FROM
0
TO
k
q=(C'[0]+A*B[0])*m
%r
C'=(C'+A*B+q*N)/r
IF
C'>=N
C'=C'-N
RETURN
C'
如果令
r=0x100000000,則
%r

/r
運算都會變得非常容易,在1024位的運
算中,循環次數k
不大於32,整個運算過程中最大的中間變數C'=(C'+A*B+q*N)
<
2*r*N
<
1057位,演算法效率就相當高了。唯一的額外負擔是需要計算
N[0]',使
N[0]*N[0]'
%r
=1,而這一問題前面已經用歐幾里德演算法解決過了,而且在模冪運
算轉化成反復模乘運算時,N是固定值,所以N[0]'只需要計算一次,負擔並不大。

『叄』 如何用python編寫一個素數環

此文主要目的,是向大家展示如何才能用python語言,來部署STARK演算法。
STARKs(可擴容的透明知識論證)是創建一種證明的技術,這項證明中f(x)=y,其中f可能要花很長的時間來進行計算,但是這個證明可以被很快驗證。STARK是「雙重擴容」:對於一個需要t步驟的計算,這會花費大約O(t * log(t))步驟才能完成這個證明,這可能是最優的情況,而且這需要通過~O(log2(t))個步驟才能驗證,對於中等大小的T值,它比原始計算快得多。STARKs也擁有隱私保護的「零知識證明」的特性,雖然我們將這類使用案例應用到其中,從而完成可驗證的延遲功能,不需要這類性質,所以我們不用擔心。
首先,先請幾項說明:
這個代碼還沒有完全審核;在實際使用案例中的情況,還不能保證
這部分代碼是還沒有達到理想狀態(是用Python語言寫的)
STARKs 的「真實情況」 傾向於使用二進制欄位而不是素數域的特定應用程序效率的原因;但是,他們確實也表現出,這里寫出的代碼是合法並且可用的。
沒有一個真實的方法來使用STARK。它是一個非常寬泛的加密和數學架構,同時為不同的應用有不同的設置,以及連續的研究來減少證明者和驗證者的復雜性,同時提高可用性。
此文希望大家能夠知道,模運算和素數域是如何運行的,
並且和多項式概念,插值和估值進行結合。
現在,讓我們一起來了解吧!
MIMC
下面是STARK的功能展示:
def mimc(inp, steps, round_constants): start_time = time.time() for i in range(steps-1): inp = (inp**3 + round_constants[i % len(round_constants)]) % molus print("MIMC computed in %.4f sec" % (time.time() - start_time)) return inp
我們選擇MIMC作為案例,因為它(i)很容易理解,(ii)在真實世界使用的很多。函數功能見下圖:
注意:在很多關於MIMC的討論中,你可以典型地看出使用了XOR,而不是+;這是因為MIMC可以在二進制情況下使用,其中添加是XOR;這里我們會在素數領域進行。
在我們的案例中,常數相對而言會是比較小的列表(例如,64位),這會一直連續地進行周期循環(也就說,在k[64]之後)。MIMC自身可以獲得這個特性,因為MIMC可以向後進行計算(從相應的輸出獲得輸入),但是往後計算需要比向前計算多花費100倍的時間(並且沒有方向可以同步進行)。所以你可以將往後計算的功能想像成計算不能同步的工作量證明,並且往前方向計算的功能可以作為驗證的過程。
x -> x(2p-1)/3 是x -> x3 的反函數;根據費馬小定理,這是真實的,盡管這個定理沒有費馬大定理出名,但是依然對數學的貢獻很大。
我們嘗試使用STARK來進行更加有效的驗證,而不是讓驗證者必須在向前方向運行MIMC,在完成向後計算之後,證明者可以在向前方向進行STARK計算,並且驗證者可以很簡單地驗證STARK。我們希望計算STARK可以比MIMC向前和向後之間的運行速度差別要小,所以證明者的時間仍然是有初始的向後計算來主導的。而並不是STARK計算。STARK的認證會相對較快(在python語言演算法中,可以是0.05-0.3秒),不論初始的計算時間有多長。
所有的計算會在2256 – 351 * 232 + 1個模內完成;我們使用素數模,因為它是小於2256 最大的素數,其中乘法群包含了232 個子集(也就是說,有這樣一個數g,從而在完全232次循環之後,G素數環的連續冪模繞回到1),而且是按照6k+5的形式。首個特性是保證FFT和FRI演算法的有效版本,其次是保證MIMC實際上可以向後計算(請見上面提到的x -> x(2p-1)/3 使用方法)。
素域操作
我們通過建立方便的等級來進行素域的操作,同時也有多項式的操作。代碼如下,收首先是小數位數:
class PrimeField(): def __init__(self, molus): # Quick primality test assert pow(2, molus, molus) == 2 self.molus = molus def add(self, x, y): return (x+y) % self.molus def sub(self, x, y): return (x-y) % self.molus def mul(self, x, y): return (x*y) % self.molus
並且使用擴展歐幾里得演算法,來計算模塊逆轉(這和在素域中計算1/x相同):
# Molar inverse using the extended Euclidean algorithm def inv(self, a): if a == 0: return 0 lm, hm = 1, 0 low, high = a % self.molus, self.molus while low > 1: r = high//low nm, new = hm-lm*r, high-low*r lm, low, hm, high = nm, new, lm, low return lm % self.molus
上面的演算法是相對昂貴的;幸運地是,對於特定的案例,我們需要做很多的模逆計算,有一個數學方法可以讓我們來計算很多逆運算,被稱為蒙哥馬利批量求逆:
使用蒙哥馬利批量求逆來計算模逆,其輸入為紫色,輸出為綠色,乘法門為黑色,紅色方塊是唯一的模逆。
下面的代碼是演算法的體現,其中包含一些特別的邏輯。如果我們正在求逆的集合中包含零,那麼它會將這些零的逆設置為 0 並繼續前進。
def multi_inv(self, values): partials = [1] for i in range(len(values)): partials.append(self.mul(partials[-1], values[i] or 1)) inv = self.inv(partials[-1]) outputs = [0] * len(values) for i in range(len(values), 0, -1): outputs[i-1] = self.mul(partials[i-1], inv) if values[i-1] else 0 inv = self.mul(inv, values[i-1] or 1) return outputs
這部分演算法接下來會驗證稱為非常重要的東西,特別是當我們開始和不同階的多項式進行計算的時候。
現在我們來看看一些多項式計算。我們把多項式當做一個數據集,其中的i是第i階(例如,x3 + 2x + 1變成[1, 2, 0, 1])。下面就是在一個點進行多項式估算的方法:
# Evaluate a polynomial at a point def eval_poly_at(self, p, x): y = 0 power_of_x = 1 for i, p_coeff in enumerate(p): y += power_of_x * p_coeff power_of_x = (power_of_x * x) % self.molus return y % self.molus
困難和挑戰
f.eval_poly_at([4, 5, 6], 2)的輸出是多少?模是31嗎?
下面的解釋就是答案
.其實也有代碼是多項式加法,減法,乘法和除法;這是很長的加減乘除運算。有一個很重要的內容是拉格朗日插值,它將一組 x 和 y 坐標作為輸入,並返回通過所有這些點的最小多項式(你可以將其視為多項式求值的逆):
# Build a polynomial that returns 0 at all specified xs def zpoly(self, xs): root = [1] for x in xs: root.insert(0, 0) for j in range(len(root)-1): root[j] -= root[j+1] * x return [x % self.molus for x in root] def lagrange_interp(self, xs, ys): # Generate master numerator polynomial, eg. (x - x1) * (x - x2) * ... * (x - xn) root = self.zpoly(xs) # Generate per-value numerator polynomials, eg. for x=x2, # (x - x1) * (x - x3) * ... * (x - xn), by dividing the master # polynomial back by each x coordinate nums = [self.div_polys(root, [-x, 1]) for x in xs] # Generate denominators by evaluating numerator polys at each x denoms = [self.eval_poly_at(nums[i], xs[i]) for i in range(len(xs))] invdenoms = self.multi_inv(denoms) # Generate output polynomial, which is the sum of the per-value numerator # polynomials rescaled to have the right y values b = [0 for y in ys] for i in range(len(xs)): yslice = self.mul(ys[i], invdenoms[i]) for j in range(len(ys)): if nums[i][j] and ys[i]: b[j] += nums[i][j] * yslice return [x % self.molus for x in b]
相關數學知識請參見此文的M-N部分。需要注意,我們也會有特別的方法lagrange_interp_4和lagrange_interp_2來加速次數小於 2 的拉格朗日插值和次數小於 4 的多項式運算。
快速傅立葉變換
如果你仔細閱讀上面的演算法,你也許會發現拉格朗日插值和多點求值(即求在N個點處次數小於N的多項式的值)都需要耗費2次時間,例如對於1000個點求拉格朗日插值,需要幾百萬個步驟,而且100萬個點的拉格朗日插值需要萬億個步驟。這是不可接受的低效率,所以我們需要使用更加有效的演算法,快速傅立葉變換。
FFT只需要花費O(n * log(n))的時間(也就是說,1000個點的計算需要10,000步,100萬個點的計算需要2000步),雖然它的范圍更受限制;x坐標必須是單位根部的完全集合,必須滿足N = 2k 階。也就是說,如果有N個點,那麼x坐標必須某個P值的連續冪,1, p, p2, p3…,其中pN = 1。這個演算法能夠用來進行多點計算和插值計算,而且只需要調整一個小參數。
下面就是演算法詳情(這是個簡單的表達方式;更詳細內容可以參閱此處代碼)
def fft(vals, molus, root_of_unity): if len(vals) == 1: return vals L = fft(vals[::2], molus, pow(root_of_unity, 2, molus)) R = fft(vals[1::2], molus, pow(root_of_unity, 2, molus)) o = [0 for i in vals] for i, (x, y) in enumerate(zip(L, R)): y_times_root = y*pow(root_of_unity, i, molus) o[i] = (x+y_times_root) % molus o[i+len(L)] = (x-y_times_root) % molus return o def inv_fft(vals, molus, root_of_unity): f = PrimeField(molus) # Inverse FFT invlen = f.inv(len(vals)) return [(x*invlen) % molus for x in fft(vals, molus, f.inv(root_of_unity))]
你可以自己通過一些輸入來運行代碼,並且看看是否能得到想要的結果,當你使用eval_poly_at的時候,給出你期望得到的答案。例如:
>>> fft.fft([3,1,4,1,5,9,2,6], 337, 85, inv=True) [46, 169, 29, 149, 126, 262, 140, 93] >>> f = poly_utils.PrimeField(337) >>> [f.eval_poly_at([46, 169, 29, 149, 126, 262, 140, 93], f.exp(85, i)) for i in range(8)] [3, 1, 4, 1, 5, 9, 2, 6]
傅里葉變換會把[x[0] …. x[n-1]]作為輸入,並且它的目標是輸出x[0] + x[1] + … + x[n-1]作為首個元素,x[0] + x[1] * 2 + … + x[n-1] * w**(n-1)作為第二個元素,等等;快速傅里葉變換可以通過把數據分為兩半,來完成這個,在兩邊都進行FFT,然後將結果結合在一起。
上圖就是信息如何進行FFT運算的解釋。請注意FFT是如何進行兩次數據復制,並且進行粘合,直到你得到一個元素。
現在,我們把所有部分組合起來,看看整件事情是如何:def mk_mimc_proof(inp, steps, round_constants),它生成運行 MIMC 函數的執行結果的證明,其中給定的輸入為步驟數。首先,是一些 assert 函數:
# Calculate the set of x coordinates xs = get_power_cycle(root_of_unity, molus) column = [] for i in range(len(xs)//4): x_poly = f.lagrange_interp_4( [xs[i+len(xs)*j//4] for j in range(4)], [values[i+len(values)*j//4] for j in range(4)], ) column.append(f.eval_poly_at(x_poly, special_x))
擴展因子是我們將要拉伸的計算軌跡(執行 MIMC 函數的「中間值」的集合)。
m2 = merkelize(column) # Pseudo-randomly select y indices to sample # (m2[1] is the Merkle root of the column) ys = get_pseudorandom_indices(m2[1], len(column), 40) # Compute the Merkle branches for the values in the polynomial and the column branches = [] for y in ys: branches.append([mk_branch(m2, y)] + [mk_branch(m, y + (len(xs) // 4) * j) for j in range(4)])
我們需要步數乘以擴展因子最多為 2^32,因為當 k > 32 時,我們沒有 2^k 次的單位根。
computational_trace_polynomial = inv_fft(computational_trace, molus, subroot) p_evaluations = fft(computational_trace_polynomial, molus, root_of_unity)
我們首個計算會是得出計算軌跡;也就是說,所有的計算中間值,從輸入到輸出。
assert steps <= 2**32 // extension_factor assert is_a_power_of_2(steps) and is_a_power_of_2(len(round_constants)) assert len(round_constants) < steps
然後,我們會從將計算軌跡轉換為多項式,在單位根 g (其中,g^steps = 1)的連續冪的軌跡上「放下」連續值,然後我們對更大的集合——即單位根 g2 的連續冪,其中 g2^steps * 8 = 1(注意 g2^8 = g)的多項式求值。
# Generate the computational trace computational_trace = [inp] for i in range(steps-1): computational_trace.append((computational_trace[-1]**3 + round_constants[i % len(round_constants)]) % molus) output = computational_trace[-1]
黑色: g1 的冪。紫色: g2 的冪。橙色:1。你可以將連續的單位根看作一個按這種方式排列的圓圈。我們沿著 g1的冪「放置」計算軌跡,然後擴展它來計算在中間值處(即 g2 的冪)的相同多項式的值。
我們可以將MIMC的循環常數轉換為多項式。因為這些循環常數鏈是非常通常發生地(在我們的測試中,每64個步驟都會進行),最終證明他們形成了64階的多項式,而且外面可以很容易計算出它的表達式,以及擴展式:
skips2 = steps // len(round_constants) constants_mini_polynomial = fft(round_constants, molus, f.exp(subroot, skips2), inv=True) constants_polynomial = [0 if i % skips2 else constants_mini_polynomial[i//skips2] for i in range(steps)] constants_mini_extension = fft(constants_mini_polynomial, molus, f.exp(root_of_unity, skips2))
假設其中有8192個步驟,並且有64個循環常數。這是我們想要做的:我們正在進行FFT,從而計算循環常數來作為g1128 的功能。然後我們在之間加入很多零,來完成g1本身的功能。因為g1128 大約每64步進行循環,我們知道g1這個功能也會同樣。我們只計算這個擴展中的512個步驟,因為我們知道這個擴展會在每512步之後重復。現在,我們按照斐波那契案例中那樣,計算C(P(x)),除了這次是計算,需要注意,我們不在計算使用系數形式的多項式;而是根據高次單位根的連續冪來對多項式進行求值。
c_of_p需要滿足Q(x) = C(P(x), P(g1*x),K(x)) = P(g1*x) – P(x)**3 – K(x);目標是對於任何我們放入計算軌道的x(除了最後一步,因為在最後一步之後,就沒有步驟),計算軌跡中的下個數值就和之前的相等,再加上循環常量。與第1部分中的斐波那契示例不同,其中如果某個計算步驟是在k向量,下個就會是k+1向量,我們把低次單位根( g1 )的連續冪放下計算軌跡,所以如果某個計算步驟是在x = g1i ,下個步驟就會在g1i+1 = g1i * g1 = x * g1。因此,對於低階單位根( g1 )的每一個冪,我們希望最終會是P(x*g1) = P(x)**3 + K(x),或者P(x*g1) – P(x)**3 – K(x) = Q(x) = 0。因此,Q(x) 會在低次單位根 g 的所有連續冪上等於零(除了最後一個)。
# Create the composed polynomial such that # C(P(x), P(g1*x), K(x)) = P(g1*x) - P(x)**3 - K(x) c_of_p_evaluations = [(p_evaluations[(i+extension_factor)%precision] - f.exp(p_evaluations[i], 3) - constants_mini_extension[i % len(constants_mini_extension)]) % molus for i in range(precision)] print('Computed C(P, K) polynomial')
有個代數定理證明,如果Q(x)在所有這些x坐標,都等於零,那麼最小多項式的乘積就會在所有這些x坐標等於零:Z(x) = (x – x_1) * (x – x_2) * … * (x – x_n)。通過證明在任何單個的坐標,Q(x)是等於零,我們想要證明這個很難,因為驗證這樣的證明比運行原始計算需要耗費更長的時間,我們會使用一個間接的方式來證明Q(x)是Z(x)的乘積。並且我們會怎麼做呢?通過證明D(x) = Q(x) / Z(x),並且使用FRI來證明它其實是個多項式,而不是個分數。
我們選擇低次單位根和高次單位根的特定排列,因為事實證明,計算Z(x),而且除以Z(x)也十分簡單:Z 的表達式是兩項的一部分。
需要注意地是,直接計算Z的分子和分母,然後使用批量模逆的方法將除以Z轉換為乘法,隨後通過 Z(X) 的逆來逐點乘以 Q(x) 的值。需要注意,對於低次單位根的冪,除了最後一個,都可以得到Z(x) = 0,所以這個計算包含其逆計算就會中斷。這是非常不幸的,雖然我們會通過簡單地修改隨機檢查和FRI演算法來堵住這個漏洞,所以就算我們計算錯誤,也沒關系。
因為Z(x)可以簡潔地表達,我們也可以獲得另個好處:驗證者對於任何特別的x,可以快速計算Z(x),而且還不需要任何提前計算。對於證明者來說,我們可以接受證明者必須處理大小等於步數的多項式,但我們不想讓驗證者做同樣的事情,因為我們希望驗證過程足夠簡潔。
# Compute D(x) = Q(x) / Z(x) # Z(x) = (x^steps - 1) / (x - x_atlast_step) z_num_evaluations = [xs[(i * steps) % precision] - 1 for i in range(precision)] z_num_inv = f.multi_inv(z_num_evaluations) z_den_evaluations = [xs[i] - last_step_position for i in range(precision)] d_evaluations = [cp * zd * zni % molus for cp, zd, zni in zip(c_of_p_evaluations, z_den_evaluations, z_num_inv)] print('Computed D polynomial')
在幾個隨機點上,進行概念檢測D(x) * Z(x) = Q(x),從而可以驗證轉賬約束,每個計算步驟是之前步驟的有效結果。但是我們也想驗證邊界約束,其中計算的輸入和輸出就是證明者所說的那樣。只是要求證明者提供P(1), D(1), P(last_step)還有D(last_step)的數值,這些都是很脆弱的;沒有證明,那些數值都是在同個多項式。所以,我們使用類似的多項式除法技巧:
# Compute interpolant of ((1, input), (x_atlast_step, output)) interpolant = f.lagrange_interp_2([1, last_step_position], [inp, output]) i_evaluations = [f.eval_poly_at(interpolant, x) for x in xs] zeropoly2 = f.mul_polys([-1, 1], [-last_step_position, 1]) inv_z2_evaluations = f.multi_inv([f.eval_poly_at(quotient, x) for x in xs]) # B = (P - I) / Z2 b_evaluations = [((p - i) * invq) % molus for p, i, invq in zip(p_evaluations, i_evaluations, inv_z2_evaluations)] print('Computed B polynomial')
那麼,我們的論證如下。證明者想要證明P(1) == input和P(last_step) == output。如果我們將I(x)作為插值,那麼就是穿越(1, input)和(last_step, output)亮點的線,於是P(x) – I(x)就會在這亮點上等於零。因此,它會證明P(x) – I(x)是P(x) – I(x)的乘積,並且我們通過提高商數來證明這點。
紫色:計算軌跡多項式 (P) 。綠色:插值 (I)(注意插值是如何構造的,其在 x = 1 處等於輸入(應該是計算軌跡的第一步),在 x=g^(steps-1) 處等於輸出(應該是計算軌跡的最後一步)。紅色:P-I。黃色:在x = 1和 x=g^(steps-1)(即 Z2)處等於 0 的最小多項式。粉紅色:(P – I) / Z2。
現在,我們來看看將P,D和B的默克爾根部組合在一起。
現在,我們需要證明P,D和B其實都是多項式,並且是最大的正確階數。但是FRI證明是很大且昂貴的,而且我們不想有三個FRI證明,所以,我們計算 P,D 和 B 的偽隨機線性組合,並且基於它來進行FRI證明:
# Compute their Merkle roots mtree = merkelize([pval.to_bytes(32, 'big') + dval.to_bytes(32, 'big') + bval.to_bytes(32, 'big') for pval, dval, bval in zip(p_evaluations, d_evaluations, b_evaluations)]) print('Computed hash root')
除非所有這三個多項式有正確的低階,不然幾乎不可能有隨機選擇的線性組合,所以這很足夠。
我們想要證明D的階數小於2 * steps,而且P 和 B 的次數小於steps,所以我們其實使用了隨機的P, P * xsteps, B, Bsteps 和 D的隨機組合,並且可以看出這部分組合是小於2 * steps。
現在,我們來檢查下所有的多項式組合。我們先獲得很多隨機的索引,然後在這些索引上為默克爾樹枝提供多項式:
k1 = int.from_bytes(blake(mtree[1] + b'\x01'), 'big') k2 = int.from_bytes(blake(mtree[1] + b'\x02'), 'big') k3 = int.from_bytes(blake(mtree[1] + b'\x03'), 'big') k4 = int.from_bytes(blake(mtree[1] + b'\x04'), 'big') # Compute the linear combination. We don't even bother calculating it # in coefficient form; we just compute the evaluations root_of_unity_to_the_steps = f.exp(root_of_unity, steps) powers = [1] for i in range(1, precision): powers.append(powers[-1] * root_of_unity_to_the_steps % molus) l_evaluations = [(d_evaluations[i] + p_evaluations[i] * k1 + p_evaluations[i] * k2 * powers[i] + b_evaluations[i] * k3 + b_evaluations[i] * powers[i] * k4) % molus for i in range(precision)]
get_pseudorandom_indices函數會回復[0…precision-1]范圍中的隨機索引,而且exclude_multiples_of參數並不會給出特定參數倍數的值。這就保證了,我們不會沿著原始計算軌跡進行采樣,否則就會獲得錯誤的答案。
證明是由一組默克爾根、經過抽查的分支以及隨機線性組合的低次證明組成:
# Do some spot checks of the Merkle tree at pseudo-random coordinates, excluding # multiples of `extension_factor` branches = [] samples = spot_check_security_factor positions = get_pseudorandom_indices(l_mtree[1], precision, samples, exclude_multiples_of=extension_factor) for pos in positions: branches.append(mk_branch(mtree, pos)) branches.append(mk_branch(mtree, (pos + skips) % precision)) branches.append(mk_branch(l_mtree, pos)) print('Computed %d spot checks' % samples)
整個證明最長的部分是默克爾樹分支,還有FRI證明,這是有更多分支來組成的。這是驗證者的實質結果:
o = [mtree[1], l_mtree[1], branches, prove_low_degree(l_evaluations, root_of_unity, steps * 2, molus, exclude_multiples_of=extension_factor)]
在每個位置,證明者需要提供一個默克爾證明,從而讓驗證者能夠檢查這個默克爾證明,並且檢查C(P(x), P(g1*x), K(x)) = Z(x) * D(x)以及B(x) * Z2(x) + I(x) = P(x)(提醒:對於不在初始計算軌道上的x,Z(x)不會是零,所以C(P(x), P(g1*x), K(x)也不會是零)。驗證者也會檢查線性組合是正確的,然後調用。
for i, pos in enumerate(positions): x = f.exp(G2, pos) x_to_the_steps = f.exp(x, steps) mbranch1 = verify_branch(m_root, pos, branches[i*3]) mbranch2 = verify_branch(m_root, (pos+skips)%precision, branches[i*3+1]) l_of_x = verify_branch(l_root, pos, branches[i*3 + 2], output_as_int=True) p_of_x = int.from_bytes(mbranch1[:32], 'big') p_of_g1x = int.from_bytes(mbranch2[:32], 'big') d_of_x = int.from_bytes(mbranch1[32:64], 'big') b_of_x = int.from_bytes(mbranch1[64:], 'big') zvalue = f.div(f.exp(x, steps) - 1, x - last_step_position) k_of_x = f.eval_poly_at(constants_mini_polynomial, f.exp(x, skips2)) # Check transition constraints Q(x) = Z(x) * D(x) assert (p_of_g1x - p_of_x ** 3 - k_of_x - zvalue * d_of_x) % molus == 0 # Check boundary constraints B(x) * Z2(x) + I(x) = P(x) interpolant = f.lagrange_interp_2([1, last_step_position], [inp, output]) zeropoly2 = f.mul_polys([-1, 1], [-last_step_position, 1]) assert (p_of_x - b_of_x * f.eval_poly_at(zeropoly2, x) - f.eval_poly_at(interpolant, x)) % molus == 0 # Check correctness of the linear combination assert (l_of_x - d_of_x - k1 * p_of_x - k2 * p_of_x * x_to_the_steps - k3 * b_of_x - k4 * b_of_x * x_to_the_steps) % molus == 0
其實還沒有完成成功;證明對跨多項式檢查和 FRI 所需的抽查次數的可靠性分析是非常棘手的。但是這些就是所有代碼,至少你不用擔心進行瘋狂的優化。當我運行以上代碼的時候,我們會獲得STARK證明,會有300-400倍的證明成本例如,一個需要 0.2 秒的 MIMC 計算需要 60 秒來證明)。這就使得4核機器計算MIMC中的 STARK,實際上可以比後向計算 MIMC 更快。也就是說,在python語言,這會相對低效的實現,並且這也會證明運行時間比例會不同。同時,也值得指出,MIMC 的 STARK 證明成本非常低,因為MIMC幾乎是完美地可計算,它的數學形式很簡單。對於平均計算,會包含更少的清晰計算(例如,檢查一個數是大於還是小於另一個),其計算成本可能會更高,會有大約10000-50000倍。

『肆』 RSA 和 蒙哥馬利乘法兩者是什麼關系

蒙哥馬利演算法是在RSA密碼系統中廣泛應用的模乘法演算法.

『伍』 千禧年七大數學難題是什麼

是NP完全問題、霍奇猜想、龐加萊猜想、黎曼假設、楊-米爾斯存在性和質量缺口、納衛爾-斯托可方程、BSD猜想。其中龐加萊猜想已被解決。

數學難題可以是指那些歷經長時間而仍未有解答/完全解答的數學問題。

古今以來,一些特意提出的數學難題有:平面幾何三大難題、希爾伯特的23個問題、世界三大數學猜想、千禧年大獎難題等。

費爾馬大定理起源於三百多年前,挑戰人類3個世紀,多次震驚全世界,耗盡人類眾多最傑出大腦的精力,也讓千千萬萬業余者痴迷。終於在1994年被安德魯·懷爾斯攻克。

古希臘數學家丟番圖寫過一本著名的《算術》(Arithmetica),經歷中世紀的愚昧黑暗到文藝復興的時候,《算術》的殘本重新被發現研究。

1637年,法國業余大數學家費爾馬(Pierre de Fremat)在《算術》的關於勾股數問題的頁邊上,寫下猜想:xn+ yn=zn是不可能的(這里n大於2;x,y,z,n都是非零整數)。

此猜想後來就稱為費爾馬大定理。費爾馬還寫道「我對此有絕妙的證明,但此頁邊太窄寫不下」。一般公認,他當時不可能有正確的證明。猜想提出後,經歐拉等數代天才努力,200年間只解決了n=3,4,5,7四種情形。

1847年,庫默爾創立「代數數論」這一現代重要學科。他還證明了當n﹤100時,除卻n=37、59、67這些不規則質數的情況,費爾馬大定理都成立,是一次大飛躍。

歷史上費爾馬大定理高潮迭起,傳奇不斷。其驚人的魅力,曾在最後時刻挽救自殺青年於不死。他就是德國的沃爾夫斯克勒,他於1908年為費爾馬大定理設懸賞10萬馬克(相當於現時的160萬美元多),期限1908-2007年。

無數人耗盡心力,空留浩嘆。最現代的電腦加數學技巧,驗證了400萬以內的n,但這對最終證明無濟於事。1983年德國的法爾廷斯證明了:對任一固定的n,最多隻有有限多個x,y,z,振動了世界,獲得菲爾茲獎(數學界最高獎)。

『陸』 跪求蒙哥瑪利模冪演算法的代碼解釋

最近在學習RSA演算法的相關知識,對於其中的核心模密運算以及模密運算的核心——模乘也開始有一點點了解。蒙哥馬利模乘的優點在於減少了取模的次數(在大數的條件下)以及簡化了除法的復雜度(在2的k次冪的進制下除法僅需要進行左移操作)。一般的模密是調用模乘運算來實現的(正如你所列的代碼),可以看一下下面一段文字(選自hellman2000的博客):

模冪運算是RSA 的核心演算法,最直接地決定了RSA 演算法的性能。針對快速模冪
運算這一課題,西方現代數學家提出了大量的解決方案,通常都是先將冪模運算轉
化為乘模運算。

例如求D=C**15 % N,由於:a*b % n = (a % n)*(b % n) % n,所以:

C1 =C*C % N =C**2 % N
C2 =C1*C % N =C**3 % N
C3 =C2*C2 % N =C**6 % N
C4 =C3*C % N =C**7 % N
C5 =C4*C4 % N =C**14 % N
C6 =C5*C % N =C**15 % N

即:對於E=15的冪模運算可分解為6 個乘模運算,歸納分析以上方法可以發現
對於任意E,都可採用以下演算法計算D=C**E % N:

D=1
WHILE E>=0
IF E%2=0
C=C*C % N
E=E/2
ELSE
D=D*C % N
E=E-1
RETURN D

繼續分析會發現,要知道E 何時能整除 2,並不需要反復進行減一或除二的操
作,只需驗證E 的二進制各位是0 還是1 就可以了,從左至右或從右至左驗證都可
以,從左至右會更簡潔,設E=Sum[i=0 to n](E*2**i),0<=E<=1,則:

D=1
FOR i=n TO 0
D=D*D % N
IF E=1 D=D*C % N
RETURN D

這樣,模冪運算就轉化成了一系列的模乘運算。

其他一些關於大數運算、素數測試、模乘、模密運算,hellman2000的一篇文章有比較全面易懂的介紹,鏈接如下:http://bbs.s.e.cn/pc/pccon.php?id=1308&nid=43763&pid=0&tag=0&tid=0

『柒』 C#里如何對位數很長的數字(已處理為字元串)轉化為16進制

.NET 4.0 中可以引用 System.Numeric 類,用 BigInteger 這個類來進行計算(P.S. 據說有精度上的問題)。

一般的解決辦法是自己寫一個類型來儲存這種超大數,當成 string 類型來處理,並自己寫演算法來對應加減乘除這些。

暫時只能想到一個效率很低的思路,這么大的數要直接轉成16進制的話演算法是很麻煩的,建議先轉成2進制,用短除法(除法的本質是多次減法,當然如果題主演算法好可以用蒙哥馬利演算法來直接做除法。當作 string 類型來計算,先截取最後一位,看夠不夠減2,夠了就把減去的結果替換掉 string 最後一位;不夠就再截取最後兩位看,依次類推。除法就是反復做減法,直到最後一次減法結果要變負數為止,商和余數就出來了)。再把2進制轉換成16進制就容易多了,從後往前每4位截斷一下,最前面不足位用0補齊,然後每四位轉換成16進制,最後拼接一下。

『捌』 蒙哥馬利冪模運算的特點及原理

蒙哥馬利模乘的優點在於減少了取模的次數(在大數的條件下)以及簡化了除法的復雜度(在2的k次冪的進制下除法僅需要進行左移操作)。模冪運算是RSA 的核心演算法,最直接地決定了RSA 演算法的性能。
針對快速模冪運算這一課題,西方現代數學家提出了大量的解決方案,通常都是先將冪模運算轉化為乘模運算。
例如求D=C^15%N
由於:a*b % n = (a % n)*(b % n) % n
所以令:
C1 =C*C % N =C^2 % N
C2 =C1*C % N =C^3 % N
C3 =C2*C2 % N =C^6 % N
C4 =C3*C % N =C^7 % N
C5 =C4*C4 % N =C^14 % N
C6 =C5*C % N =C^15 % N
即:對於E=15的冪模運算可分解為6 個乘模運算,歸納分析以上方法可以發現:
對於任意指數E,都可採用以下演算法計算D=C**E % N:
D=1
WHILE E>0
IF E%2=0
C=C*C % N
E=E/2
ELSE
D=D*C % N
E=E-1
RETURN D
繼續分析會發現,要知道E 何時能整除 2,並不需要反復進行減一或除二的操作,只需驗證E 的二進制各位是0 還是1 就可以了,從左至右或從右至左驗證都可以,從左至右會更簡潔,
設E=Sum[i=0 to n](E*2**i),0<=E<=1
則:
D=1
FOR i=n TO 0
C=C*C % N
IF E=1
D=D*C % N
RETURN D這樣,模冪運算就轉化成了一系列的模乘運算。

『玖』 c++中如何計算244^847%2773的值 ,最好有一個簡單的程序。

模冪演算法見高爺爺的大作《計算機程序設計藝術(第二卷)》,指數按二進制位掃描,可以從低到高,也可以從高到低,兩者計演算法略微不同,這里給出從低到高掃描的方法,遇到bit1,則執行if裡面的運算,否則,a平方並模m

程序沒做太多的參數檢查,例如m為0的情況,也沒做優化,比如a是0或者1的情況
unsigned int mod_exp(unsigned int a, unsigned int p, unsigned int m)
{
unsigned int res = 1;

for (a = a % m; p != 0; p >>= 1)
{
if ((p & 0x01) != 0)
{
res = (res * a) % m;
}

a = (a * a) % m;
}

return res;
}
因為不是大數模冪,沒有做滑動窗口、蒙哥馬利演算法之類的優化,直來直去直接計算

『拾』 請教RSA加密中大數運算中蒙哥馬利演算法

http://wenku..com/link?url=-aIgFy7FR29nO3Sz70QbXhh3-2D3xZX6a-

熱點內容
安卓怎麼轉移數據華為 發布:2025-01-15 21:03:02 瀏覽:140
軟體列印反饋單腳本錯誤 發布:2025-01-15 21:01:24 瀏覽:177
如何進cs里的練槍伺服器 發布:2025-01-15 21:00:07 瀏覽:979
蘋果手機存儲晶元 發布:2025-01-15 20:52:02 瀏覽:162
盲人讀屏軟體安卓哪個好 發布:2025-01-15 20:47:13 瀏覽:728
炸圖腳本 發布:2025-01-15 19:56:07 瀏覽:429
八字源碼 發布:2025-01-15 19:54:47 瀏覽:372
伺服器可以變電腦使用嗎 發布:2025-01-15 19:40:29 瀏覽:202
傳奇手游免費腳本 發布:2025-01-15 19:30:21 瀏覽:300
我國當前資源配置存在哪些問題 發布:2025-01-15 19:25:03 瀏覽:514