Pebble Coding

ソフトウェアエンジニアによるIT技術、数学の備忘録

ed25519のpython実装を紐解く その3 暗号編テスト

ed25519のpython実装を紐解く 暗号編 その1(キーペア生成からベリファイまで) - Pebble Coding

リファレンス実装では、sign.inputというファイルの中に:区切りでの
秘密鍵,公開鍵,メッセージ,署名+メッセージのセットがhex表示で1024個入っています。
例として3行目のデータを取り出します。

c5aa8df43f9f837bedb7442f31dcb7b166d38535076f094b85ce3a2e0b4458f7fc51cd8e6218a1a38da47ed00230f0580816ed13ba3303ac5deb911548908025  
:fc51cd8e6218a1a38da47ed00230f0580816ed13ba3303ac5deb911548908025  
:af82  
:6291d657deec24024827e69c3abe01a30ce548a284743a445e3680d7db5ac3ac18ff9b538d16f290ae67f760984dc6594a7c15e9716ed28dc027beceea1ec40aaf82  
:

1列目が秘密鍵32バイト+公開鍵32バイトです。
c5aa8df43f9f837bedb7442f31dcb7b166d38535076f094b85ce3a2e0b4458f7fc51cd8e6218a1a38da47ed00230f0580816ed13ba3303ac5deb911548908025

2列目が公開鍵32バイトです。
fc51cd8e6218a1a38da47ed00230f0580816ed13ba3303ac5deb911548908025

3列目がメッセージです。
1行目が0バイト,2行目が1バイト,...,1024行目が1023バイトとなっているようです。
ここでは2バイトです。
af82

4列目が署名64バイト+元のメッセージです。 ここでは64バイト+2バイトです。 6291d657deec24024827e69c3abe01a30ce548a284743a445e3680d7db5ac3ac18ff9b538d16f290ae67f760984dc6594a7c15e9716ed28dc027beceea1ec40aaf82

以下のコマンドで1024のセットに対して検証が行われます。

$ sign.py < ./sign.input

MacBookPro 2017で試すと、1つの行の処理に7秒ほどかかります。

検証プログラムの中身を見ていきましょう。

import sys
import binascii
import ed25519

# examples of inputs: see sign.input
# should produce no output: python sign.py < sign.input

# warning: currently 37 seconds/line on a fast machine

# fields on each input line: sk, pk, m, sm
# each field hex
# each field colon-terminated
# sk includes pk at end
# sm includes m at end

while 1:
  line = sys.stdin.readline()
  if not line: break
  x = line.split(':')
  sk = binascii.unhexlify(x[0][0:64])
  pk = ed25519.publickey(sk)
  m = binascii.unhexlify(x[2])
  s = ed25519.signature(m,sk,pk)
  ed25519.checkvalid(s,m,pk)
  forgedsuccess = 0
  try:
    if len(m) == 0:
      forgedm = "x"
    else:
      forgedmlen = len(m)
      forgedm = ''.join([chr(ord(m[i])+(i==forgedmlen-1)) for i in range(forgedmlen)])
    ed25519.checkvalid(s,forgedm,pk)
    forgedsuccess = 1
  except:
    pass
  assert not forgedsuccess
  assert x[0] == binascii.hexlify(sk + pk)
  assert x[1] == binascii.hexlify(pk)
  assert x[3] == binascii.hexlify(s + m)

pk = ed25519.publickey(sk)
秘密鍵から公開鍵を計算し、メッセージの署名を計算しています。
ed25519.checkvalidで計算した署名が正しいかを確認しています。
そのあと実施しているforgedでは、メッセージバイト列の最後のバイトに1を追加した場合、
署名が一致しなくなることを確認しています。
その後、公開鍵が ファイル内の値と一致すること、
署名+メッセージがファイル内の値と一致することを確認しています。