簽名s應當是祕密數字x,消息的哈希值H(m)和隨機數字k的一個函數。s=f(x,H(m),k)安全
咱們如何在不知道x和k的狀況下驗證該等式呢。函數
咱們能夠藉助於上章學習的離散對數問題。y=g^x mod p 和r=g^k mod p發送給接受者,不用擔憂x和k的泄露。通常稱x爲私鑰,y爲公鑰,<r,s>爲數字簽名。學習
簽名關係F和簽名函數f是等價的,而驗籤關係G是由F決定的。所以關係F是決定簽名方案的關鍵。設計
咱們最容易想到的一種方案是讓 中各數字之間有加法運算,如:對象
s=x+k+H(m)mod(p-1)數學
因此,G應當爲:g^s≡g^(x+k+H(m)) mod p=g^xg^kg^H(m) mod p≡yr g^H(m) mod p比特幣
因此,接收方須要驗證關係:g^s≡yr * g^H(m) mod p是否成立就能夠驗證簽名了。隨機數
可是目前仍然存在問題,即正常的簽名是能夠經過驗證的啊,可是可能被攻擊者進行攻擊。攻擊者很容易在不知曉x和k的狀況下,僞造簽名r和s。總結
那麼如何進行僞造呢?安全性
攻擊者只要先對s任取一值s’,而後經過解方程g^s≡yr * g^H(m) mod p,獲得r'≡g^s'/(y * g^H(m)) mod p。
顯然知足上述公式的r'和s'也能夠驗證經過。
因此咱們必須修改方案,能夠藉助上面學習的離散對數問題,可讓驗籤方案中的s和都出如今指數上,這樣攻擊者就必須解決離散對數問題,纔可能實施攻擊。因此咱們須要調整驗籤方案G和簽名方案F。
咱們能夠將簽名關係F修改成:sk≡H(m)+xr (mod (p-1)),則簽名函數s爲s=(H(m)+xr) /k mod(p-1),即k=(H(m)+xr) /s mod(p-1),因此有:r=g^k mod p=g^(H(m)+xr)/s mod p=g^(H(m))/s * g^(r/s) mod p
在該等式的結果中,僅包含簽名<r,s>,公鑰y和消息m,不會泄露私鑰x,k。因此可使用該等式做爲驗籤關係:
G:r=g^(H(m))/s * g^(r/s) mod p因爲r和s都在指數上,因此攻擊者沒法僞造簽名。
總計一下,咱們的DSA的簽名方案爲:
r=g^k mod p;
s=(H(m)+xr) /k mod(p-1)
驗籤方案爲:
r=g^(H(m))/s * g^(r/s) mod p
事實上,上面的方案仍是存在着不足,即爲了防止離散對數數學問題不被暴力破解,一般素數p的值須要很大,爲了減少數字簽名的規模,咱們須要採起必定的措施:
選擇一個相對較小的整數q,使q知足g^q mod p=1,若是 p取1024比特,那麼q就取160比特。
這樣,s和q修改成相同的規模,r的大小不變。因此咱們須要把r縮減爲同等規模。即r修改成
r= (g^(H(m)/s * y^(r/s) mod p)) mod q;
到此,咱們總結下,DSA的簽名方案爲:
簽名過程:
第一步,生成參數素數p,素數q,底數 g,知足g^q mod p=1;
第二步,對任意消息m,生成隨機數 k,1<k<q;
第三步,計算r=(g^k mod p) mod p,若r=0,重複該步驟;
第四步,計算s=(H(m)+xr)/k mod q,若 s=0,重複該步驟;
第五步,令<r,s>爲數字簽名。
驗證過程:
檢查該過程是否成立:
總結:
第一,爲了防止泄露私鑰 ,只能公開公鑰 ;
第二,爲了防止僞造簽名,必須在驗籤方案中讓簽名出如今指數上;
第三,爲了減少數字簽名規模,爲指數選擇一個相對較小的模數。
而這一切都創建在素數域GF(p)中的整數加法、乘法、冪和離散對數的運算性質上。
若是將素數域更換爲有限域上的橢圓曲線,運算的對象變爲橢圓曲線上的點,那麼仍然能夠定義出具備相似性質的加法、乘法。參照咱們的DSA探祕之路,你本身就能夠設計出具備更高安全性的橢圓曲線數字簽名方案ECDSA,而ECDSA正是比特幣體系使用的數字簽名方案。