EdDSA
RFC 8032 エドワーズ曲線デジタル署名アルゴリズム Edwards-Curve Digital Signature Algorithm (EdDSA)
RFC 7748 セキュリティのための楕円曲線 Elliptic Curves for Security Ed448-Goldilocks
NIST SP 800-186 Recommendations for Discrete Logarithm-based Cryptography: Elliptic Curve Domain Parameters NIST FIPS 186-5 Digital Signature Standard (DSS)
日本語の資料?
ディジタル署名アルゴリズム EdDSA の実装性能調査
ディジタル署名 EdDSA の構成の安全性に関する調査および評価
RFC 6090 基本的な楕円曲線暗号アルゴリズム Fundamental Elliptic Curve Cryptography Algorithms ssh では利用できるがhttps TLSでは1.3で正式対応? 未対応の環境がまだある 利用
RFC 8410 Algorithm Identifiers for Ed25519, Ed448, X25519, and X448 for Use in the Internet X.509 Public Key Infrastructure RFC 8709 Ed25519 and Ed448 Public Key Algorithms for the Secure Shell (SSH) Protocol RFC 8037 CFRG Elliptic Curve Diffie-Hellman (ECDH) and Signatures in JSON Object Signing and Encryption (JOSE) RFC 8419 Use of Edwards-Curve 電子署名アルゴリズム (EdDSA) 署名 in the Cryptographic Message Syntax (CMS) RFC 8420 Using the Edwards-Curve 電子署名アルゴリズム (EdDSA) in the Internet Key Exchange Protocol Version 2 (IKEv2) 一般的なものと、署名に使われている特定の曲線と2段階くらいある
RFC 7748と8032は特定の曲線を使ったもの
実装はRFC 8032だけでも読めば可(ハッシュ関数SHA-512, SHAKE256は別途必要)
署名
ハッシュ込みなので短い固定長データのみ対象ではない
暗号化では元の値に戻る必要があるが、署名ではハッシュ関数と同じように戻る必要がないのでDSA系は一方通行な計算をする EdDSAでも直接暗号には利用できない
[s]B という計算が楕円曲線の部分という闇に一旦置いておくと次のように簡単
Bは基準になる点 x, y座標が各アルゴリズムで1つ決まっている
(足し算[a]B + [b]B = [a+b]B、掛け算[a][b]B = [a*b]Bができるよ)
$ B^sを楕円曲線上に置き換えたもの、ということで使う側からは大した違いはない
ざっくりした解説
鍵の生成
秘密鍵 乱数 dビットの乱数 長さを変えても使えそうだが強度への影響は不明
h 秘密鍵のハッシュ、乱数の代わりに使用する、鍵ごとに特定の値が得られる
h = H(秘密鍵) SHA512(64byte) または SHAKE256(114byte出力)
ha と hb の2つに分ける
h | 前半 s の元 | 後半 prefix |
ha を符号なしlittle endianで数値化し、スカラーs とする
hb は ハッシュの前に入れるprefix として使用する
[s]Bな計算をしたものが公開鍵A
AのY座標の最上位ビットにX座標の最下位ビットを載せたものが座標をバイト列に符号化したもの
XはY座標から復元可能
秘密鍵と秘密鍵から生成される成分(h,s,prefix)は秘密
公開鍵Aからsは逆算できない
PureEdDSAの場合 (Ed448はprefixの前にdom4が必要)
署名
メッセージ M
r = H( prefix || M ) // DSA, ECDSA では乱数な部分
R = [r]B
k = H( R || A || M)
S = (r + k * s) mod L
署名 = R || S
検証
署名からRとS
公開鍵 A
h = H( R || A || M) (mod L)
[S]B = R + [h]A
[r+k*s]B = [r]B + [h][s]B
h = k からMの証明
[s]Bの計算はガロア体と同じようにざっくり合わせられる
基準になるBは楕円曲線ごとに指定あり
's'回足したり掛けたりしたものが新しい点で、足し算掛け算ができそうな感じ 楕円曲線は掛け算を楕円曲線のPointからの掛け算に置き換えたもの
ECDSAでは例外の計算があったが、EdDSAでは例外的な計算が必要ない曲線を使用する
PureEdDSAとHashEdDSAがある RFC 8419 CMSやRFC 8446 TLS 1.3ではPureEdDSAを使用
リトルエンディアンを採用、Intel系などに最適化
ハッシュアルゴリズムとハッシュサイズが決まっているのでECDSAより署名用OIDも少なかったりする?
table:種類
署名用 暗号用(鍵交換・旧)
秘密鍵長(bit) 256 456 256
公開鍵長(bit) 256 456 256 456
署名長 512 912
秘密鍵はハッシュにかけられるので可変長でもいいのかも
語
有限群 finite groups
群 groups
逆元 reverse element
ぐらいがあればいい?
秘密鍵を作ってみる
EdDSAの鍵はOCTETSTRINGに入れてあるのでそうするだけ
code:Java
package てきとう;
import java.security.SecureRandom;
import net.siisise.iso.asn1.tag.ASN1DERFormat;
import net.siisise.iso.asn1.tag.OCTETSTRING;
public class EdDSA {
// Ed25519 (仮)
static final int b = 256;
public byte[] genPrivateKey() {
byte[] key = new byteb/8; try {
SecureRandom srnd = SecureRandom.getInstanceStrong();
srnd.nextBytes(key);
OCTETSTRING oct = new OCTETSTRING(key);
ASN1DERFormat der = new ASN1DERFormat();
return oct.rebind(der);
} catch (NoSuchAlgorithmException e) {
// ないので略
throw new IllegalStateException(e);
}
}
}
公開鍵
秘密鍵keyをハッシュSHA512にかけた512bit(64byte)の下位 h[0..31] を使う
最下位3bitをクリアする 先頭バイト key[0] &= 0xfc
最上位2bitを01にする 最終バイト key[31] = (key[31] & 0x7f) | 0x40
Little Endian で数字化 s
スカラー倍算 [s] B を実行する
y座標をLittle Endianで文字列に変換
x座標の最下位ビットをy最上位ビットにもってくる
結果が公開鍵
同じ鍵長で3種類のあるごりずむ
table:種類
PureEdDSA context拡張 HashEdDSA
符号名的なもの Ed25519 Ed448 Ed25519ctx Ed25519ph Ed448ph
phflag 0 0 1 1
context(最大255) なし (空文字) あり(必須) なし(空文字列)
dom2(phflag, context) 空 dom4(0,"") (0,context) (1,"")
HashEdDSA(Ed25519ph)はアルゴリズム内でハッシュ計算する場合 (1pass?)
PureEdDSA(Ed25519)は事前にハッシュ化されているものを使ったりする場合(アルゴリズムは同じ? 2pass?)
Ed25519ctx は PureEdDSAにAES-GCM(AEAD)やcSHAKEで使うような追加のパラメータに相当するものを使う場合
PureEdDSA Ed448はcontext拡張相当の形でdom4を省略せず動作する Ed448ctxは存在しない
特に何もなければPureEdDSAを使っているよ
id-X25519 OBJECT IDENTIFIER ::= { 1 3 101 110 }
id-X448 OBJECT IDENTIFIER ::= { 1 3 101 111 }
id-Ed25519 OBJECT IDENTIFIER ::= { 1 3 101 112 }
id-Ed448 OBJECT IDENTIFIER ::= { 1 3 101 113 }
code:RFC 8419 2.2. 2.3
sigAlg-Ed25519 ALGORITHM ::= { OID id-Ed25519 }
sigAlg-Ed448 ALGORITHM ::= { OID id-Ed448 }
hashAlg-SHA-512 ALGORITHM ::= { OID id-sha512 }
hashAlg-SHAKE256 ALGORITHM ::= { OID id-shake256 }
hashAlg-SHAKE256-LEN ALGORITHM ::= { OID id-shake256-len
PARAMS ShakeOutputLen }
hashAlgs OBJECT IDENTIFIER ::= { joint-iso-itu-t(2)
country(16) us(840) organization(1)
gov(101) csor(3) nistalgorithm(4) 2 }
id-sha512 OBJECT IDENTIFIER ::= { hashAlgs 3 }
id-shake256 OBJECT IDENTIFIER ::= { hashAlgs 12 }
id-shake256-len OBJECT IDENTIFIER ::= { hashAlgs 18 }
ShakeOutputLen ::= INTEGER -- ビット出力長
秘密鍵
algorithm AlgorithmIdentifier(OIDのみ パラメータはnullもなし)
privateKey PrivateKey
privateKey は中身もOCTETSTRINGなので2重になっている Ed25519は32byte
(ECDSAの場合はOCTETSTRING内にバイナリ直書き?)
$ v^2 = u^3 + Au^2 + u
Ax^2 + y^2 = 1 + Dx^2y^2
$ x^2 + y^2 = 1 + dx^2y^2 for 素数 p p = 3 mod 4の場合
ツイストエドワーズ曲線$ -x^2 + y^2 = 1 + dx^2y^2 p = 1 mod 4 の場合
RFC 8032 3 EdDSA
よくわからない11のパラメータ
1. 奇数の素数 p 楕円曲線は有限体 GF(p) を使う
p = $ 2^{255} - 19 (Ed25519)
p = $ 2^{448} - 2^{224} - 1 (Ed448)
2. $ 2^{b-1} > p の整数 b 公開風サイズ、署名サイズは b * 2
$ b = 256 (Ed25519)
$ b = 456 (Ed448)
3. 有限体GF(p)の要素 A (b-1) bit出力 どれ?
ENCのこと?
4. 2b bit 出力する暗号ハッシュ関数 H SHA512
H SHA512 (Ed25519)
H SHAKE256(114byte) (Ed448)
5. 整数c 2 または 3 EdDSAスカラーは $ 2^c の倍数? 0埋めする目安?
$ c = 3 (Ed25519)
cofactor = $ 2^c = 8
$ c = 2 (Ed448)
cofactor = $ 2^c = 4
6. $ c <= n < bの整数 n EdDSAスカラーを n+1 bit にするためにフラグを立てる位置が$ 2^n
$ n = 254 (Ed25519)
$ n = 447 (Ed448)
7. GF(p)のnon-squate element(非正方形要素) d 0に最も近い値?
$ d = -121665/121666 (Ed25519)
$ d = -39081 (Ed448)
8. GF(p)の非ゼロのsquate element(正方形要素) a 推奨 p mod 4 = 1 のとき -1 p mod 4 = 3のとき 1
$ a = -1 (Ed25519)
$ a = 1 (Ed448)
9. 要素 B != (0,1) は セット E = {{x, y} は GF(p)xGF(p)のメンバー a * x^2 + y^2 = 1 + d * x^2 * y^2 } ?
x は yから計算できるのでyだけでもいい
10. 奇数素数 L, [L]B = 0および 2^c * L = #E
cofactor * order
order とL?はべき乗で元に戻る値
11. プリハッシュ PH(x) PureEdDSAではなにもしない PH(M) = M
$ PH(x) = x (PureEdDSA)
PH(x) = SHA512(x) (Ed25519ph)
PH(x) = SHAKE256(x,64byte) (Ed448ph)
秘密鍵の長さは固定ではない? SHA512のブロック長は?
RFC 8032 5.1 表1 Ed25519のパラメータ
table:Ed25519ph, Ed25519ctx, Ed25519
p 2^255 - 19 RFC 8032 1, 7748
b 256 RFC 8032 2
鍵長, 署名/2?
GF(p)の符号化 255-bit little-endian of {0, 1, ... p-1}
H(x) SHA-512(dom2(phflag,context)||x) RFC 8032 4, RFC 6234
c 3 RFC 8032 5
edwards25519のcofactor = 2^c の2を底とする対数 RFC 7748
n 254 RFC 8032 6
d -121665/121666 RFC 8032 7
= 370957059346694393431380835087545651895421138798432
19016388785533085940283555 RFC 7748
a -1 RFC 8032 8 RFC 7748 d
B (X(P),Y(P)) RFC 8032 9 RFC 7748
(151122213495354007725011514095885315114540126930418572060
46113283949847762202, 4631683569492647816942839400347
5163141307993866256225615783033603165251855960)
L 2^252+27742317777372353535851937790883648493 order? RFC 8032 10 RFC 7748
order 2^252 + 0x14def9dea2f79cd65812631a5cf5d3ed
PH(x) x RFC 8032 11
他
cofactor 8 = 2^c
A 486662 RFC 8032 3
dom2 PureEdDSAでは空文字 RFC 8032 4
符号化が増えてAが減っている?
Ed25519
H(x) 2*b bit出力できる暗号化ハッシュ関数 Ed25519の場合は512bitのSHA-512
整数c 2または3 3固定 EdDSAスカラーは 2^c の倍数らしい スカラー(秘密鍵の値)の下位cビットをクリアする
c <= n < b の整数 n 正確に n + 1 bitの秘密鍵にするための 2^nを設定するための値 n = b - 1 くらい
GF(p)の非正方形要素d 謎の値
2*b 署名長、ハッシュ
p は素数、GF(p)の上でいろいろする
Ed25519の場合、dom2(f,c)は空文字列です。phflagの値は無関係です。コンテキスト(存在する場合)は空でなければなりません。これにより、スキームは以前に公開されたEd25519スキームと完全に同一になります。
Ed25519
dom2(f,c) は空文字
phflag の値は無関係 ( PH(x) で未使用)
Ed25519ctx コンテキストそのまま?
Ed25519ph ハッシュから?
Ed448 は RFC 7748 では4.2.の3つある内の後の方、EdWards448だったりGoldilocks と呼ばれる方を使う d と B が違うので注意
table:Ed448
Parameter edwards448
p 2^448 - 2^224 - 1 RFC 7748
b 456
GF(p)の符号化 455-bit little-endian of {0, 1, ..., p - 1}
H(x) SHAKE256(dom4(phflag,context)||x, 114)
phflag 0
c 2
edwards448の2を底とする対数 RFC 7748
n 447
d -39081 RFC 7748
a 1
B (X(P),Y(P))
(22458004029592430018760433409989603624678964163256413424612
54616869504154674060329090291928693579532825780320751
46446173674602635247710, 2988192100784814926760179304
43930673437544040154080242095928241372331506189835876
003536878655418784733982303233503462500531545062832660)
L 2^446 - 1381806680989511535200738674851542688033669247488217860989
4547503885
PH(x) x
ECDSAと似ているが乱数っぽいもの(nonce)の生成が手順に入っているためより安全? ブラウザではSafari以外が未サポート(TLS 1.3以降でサポート可?)
table:強度
種類 強度bit 公開鍵長byte 署名byte, ハッシュ長 ハッシュ関数
Ed25519 128 32 (256bit) 64 (512bit) SHA-512 Ed448 224 57 (456bit) 114 (912bit) SHAKE256 パラメータは11あるが多すぎるのでセットで定義されたものを使う
ECDSAでよく使われる曲線(NISTなどが定義しているもの)とは別のEd25519とEd448があるようだ。Ed25519が一般的に使われる
p の値が $ 2^{255} - 19 なところから Ed25519
Ed448 は $ 2^{448} - 2^{224} - 1
訳(仮 わかってない)
RFC 8032 の 2
GF(p) p要素の有限体
[n]X X自体をn回追加
h[i] オクテット列のi番目のオクテット
h_i hのiビット目
dom2(int x, byte[] y)
Ed25519の署名・検証で使う空のオクテット列
"SigEd25519 no Ed25519 collisions" || octet(x) || octet(OLEN(y)) || y
x は 0 から 255 の値 y は 255オクテットまでのオクテット列
PureEdDSAでは省略されている
dom4(int x, byte[] y)
Ed448の署名・検証で使う空のオクテット列
"SigEd448" || octet(x) || octet(OLEN(y)) || y
注) こちらは省略できない
2. 表記法と規則
このドキュメントでは、以下の表記法が使用されています。
p 基底体を定義する素数
GF(p) p 個の元(elements)を持つ有限体(Finite field) $ x^y または x^y x を自身に y 回乗じた値
B 対象の群または部分群の生成元
[n]X X を自身に n 回加算した値
h[i] オクテット列の i 番目のオクテット
$ h_i または h_i h の i 番目のビット
a || b (ビット)文字列 a と(ビット)文字列 b の連結
a <= b a は b 以下
a >= b a は b 以上
i+j i と j の和(加算 sum)
i*j i と j の乗算(multiplication)
i-j i から j を減算(subtraction)
i/j i を j で割る(除算 division)
i x j i と j の直積(cartesian product)
(u,v) x 座標が u、y 座標が v の楕円曲線上の点
SHAKE256(x, y) 入力 x に対する SHAKE256 FIPS202 の最初の y オクテット出力 OCTET(x) 値 x を持つオクテット
OLEN(x) 文字列 x のオクテット数
dom2(x, y) Ed25519の署名または検証時は空のオクテット文字列。それ以外の場合、オクテット文字列は「SigEd25519 no Ed25519 collisions」|| octet(x) || octet(OLEN(y)) || y。ここで、xは0~255の範囲、yは最大255オクテットのオクテット文字列です。「SigEd25519 no Ed25519 collisions」はASCII(32オクテット)です。
dom4(x, y) オクテット文字列「SigEd448」|| octet(x) || octet(OLEN(y)) || y。ここで、xは0~255の範囲、yは最大255オクテットのオクテット文字列です。 「SigEd448」は ASCII (8 オクテット) です。
括弧(つまり「(」と「)」)は式をグループ化するために使用されます。これは、演算子間の結合順序に依存した記述を避けるためです。
ビット文字列は、ビットを左から右へ取り、各オクテットの最下位ビットから最上位ビットへとパックし、各オクテットがいっぱいになったら次のオクテットに移動することで、オクテット文字列に変換されます。オクテット文字列からビット文字列への変換は、このプロセスの逆です。例えば、16ビットのビット文字列
b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 b10 b11 b12 b13 b14 b15
は、2つのオクテット x0 と x1 に(この順序で)変換されます。
x0 = b7*128+b6*64+b5*32+b4*16+b3*8+b2*4+b1*2+b0
x1 = b15*128+b14*64+b13*32+b12*16+b11*8+b10*4+b9*2+b8
リトルエンディアン方式によるビットへのエンコードでは、ビットは左から右へ、最下位ビットから最上位ビットへと配置されます。上記で定義したビット文字列からオクテット文字列への変換と組み合わせると、リトルエンディアン方式によるオクテットへのエンコードが行われます(長さが8の倍数でない場合、最後のオクテットの最上位ビットは未使用のままになります)。
この文書におけるキーワード「しなければならない(MUST)」、「してはならない(MUST NOT)」、「必須(REQUIRED)」、「するものとする(SHALL)」、「するべきではない(SHALL NOT)」、「すべきである(SHOULD)」、「すべきでない(SHOULD NOT)」、「推奨される(RECOMMENDED)」、「してもよい(MAY)」、「任意(OPTIONAL)」は、RFC2119 に記述されているとおりに解釈されます。 3. EdDSA アルゴリズム
EdDSA は、11 個のパラメータを持つデジタル署名システムです。
11 個の入力パラメータを持つ汎用 EdDSA デジタル署名システムは、直接実装することを想定していません。パラメータの選択は、安全で効率的な運用のために重要です。代わりに、EdDSA 用の特定のパラメータ(Ed25519 や Ed448 など)を選択して実装します。場合によっては、Ed25519 と Ed448 をカバーするためにコードの再利用性を高めるために、若干の一般化を行うこともあります。
したがって、汎用 EdDSA の正確な説明は、実装者にとって特に有用ではありません。背景情報と完全性を確保するために、ここでは汎用 EdDSA アルゴリズムの簡潔な説明を示します。
n や c などのパラメータの定義は、アルゴリズムの直感的に理解しにくい手順を説明するのに役立つ場合があります。
この説明は EDDSAに厳密に従っています。
EdDSA には 11 個のパラメータがあります。
1. 奇数の素数p, EdDSAは有限体GF(p)上の楕円曲線を使用する。
2. $ 2^{b-1}>pを満たす整数b。EdDSA公開鍵は正確にb bitで署名は正確に2*b bitです。bは8の倍数がおすすめのため公開鍵と署名の長さはオクテットの整数倍になる。
3. 有限体GF(p) の要素(element)の b-1 bit出力
4. 2*b ビット出力のハッシュ関数H。衝突が起こりにくいハッシュ関数(保守的なハッシュ関数)が推奨されますが、EdDSA の総コストに大きな影響を与えません。
5. 2 または 3 の整数 c。秘密のEdDSAスカラーは 2^cの倍数です。整数cは2を底とする補数の対数(cofactor)。
6. c <= n < b の整数 n。秘密のEdDSAスカラーは n + 1 ビットで、上位ビット(2^nの位置)は常に設定され、下位cビットは常にクリアされます。
7. GF(p)の非正方形要素(non-square element) d。通常の推奨は、許容できる曲線を与えるゼロに最も近い値としてそれをとることです。
8. GF(p)の非ゼロの正方形要素(non-zero square element) a。最高のパフォーマンスを得るための通常の推奨は、 p mod 4 = 1の場合は a = -1, p mod 4 = 3 の場合は a = 1 です。
9. B != (0,1) は 集合 E = { (x,y) は GF(p) x GF(p) の元であり、a * x^2 + y^2 = 1 + d * x^2 * y^2 } が成り立ちます。
10. [L]B = 0 かつ 2^c * L = #E となる奇数素数 L。#E (曲線上の点の数)は、楕円曲線 E に提供される標準データの一部であり、または余因子 * 次数として計算することもできます。
11. 「事前ハッシュ」関数PH。PureEdDSAは、PHが恒等関数であるEdDSA(つまり、PH(M) = M)を意味します。HashEdDSAは、メッセージの長さに関係なく、PHが短い出力を生成するEdDSAを意味します(たとえば、PH(M) = SHA-512(M))。
曲線上の点は、加法のもとで群を形成し、(x3, y3) = (x1, y1) + (x2, y2)となり、次の式が成り立つ。
$ x3 = \frac{x1 * y2 + x2 * y1}{1 + d * x1 * x2 * y1 * y2} , $ y3 = \frac{y1 * y2 - a*x1*x2}{1 - d *x1* x2*y1*y2}
群の中立元は(0,1)です。
暗号アプリケーションで用いられる他の多くの曲線とは異なり、これらの式は「完全」です。つまり、曲線上のすべての点において、例外なく有効です。特に、すべての入力点において分母は非ゼロです。
3.1. 符号化 Encoding
整数 0 <= S <= L - 1 は、リトルエンディアン形式で b ビット列 ENC(S) として符号化されます。
E の要素 (x,y) は、ENC(x, y) と呼ばれる b ビット列として符号化されます。これは、y の (b-1) ビットの符号化に、x が負の場合には 1、負でない場合には 0 となる 1 ビットを連結したものです。
GF(p) の符号化は、GF(p) の「負の」要素を定義するために使用されます。具体的には、x の (b-1) ビット エンコーディングが -x の (b-1) ビット エンコーディングよりも辞書式に大きい場合、x は負になります。
3.2. 鍵 Keys
EdDSA秘密鍵はbビットの文字列kです。ハッシュ $ H(k) = (h_0, h_1, ..., h_{(2b-1)}) は整数sを決定します。これは$ 2^n に、すべての整数 i、c <= i < nについて、$ m = 2^i * h_i の和を加えたものです。sは倍数 $ A = [s]B を決定します。EdDSA公開鍵はENC(A)です。ビット $ h_b、...、h_{(2b-1)}は、以下で署名時に使用されます。
3.3. 署名 Sign
秘密鍵 k によるメッセージ M の EdDSA 署名は、PH(M) の PureEdDSA 署名として定義されます。言い換えれば、EdDSA は PureEdDSA を用いて PH(M) に署名するだけです。
秘密鍵 k によるメッセージ M の PureEdDSA 署名は、2*b ビットの文字列 ENC(R) || ENC(S) です。R と S は以下のように導出されます。
まず、リトルエンディアン形式の 2*b ビットの文字列を {0, 1, ..., 2^(2*b) - 1} の整数として解釈し、$ r = H(h_b || ... || h_{(2b-1)} || M) と定義します。$ R = [r]B 、S = (r + H(ENC(R) || ENC(A) || PH(M)) * s) mod L とします。ここで使用される s は前のセクションで使用した値です。
3.4. 検証 Verify
公開鍵ENC(A)を用いてメッセージMにPureEdDSA署名ENC(R) || ENC(S)を検証するには、以下のようにする。入力を解析し、AとRがEの要素となり、Sが集合{0, 1, ..., L-1}の要素となるようにする。h = H(ENC(R) || ENC(A) || M)を計算し、Eにおける群方程式$ [2^c * S] B = [2^c] R + [2^c * h] A が成立するかどうかを検証する。解析が失敗した場合(Sが範囲外の場合を含む)、または群方程式が成立しない場合、署名は拒否される。
メッセージMに対するEdDSA検証は、PH(M)に対するPureEdDSA検証と定義される。
4. PureEdDSA、HashEdDSA、および命名 Naming
EdDSAアルゴリズムのパラメータの一つに「プレハッシュ」関数があります。PureEdDSAというアルゴリズムでは恒等関数の場合もあり、HashEdDSAというアルゴリズムではSHA-512のような衝突耐性ハッシュ関数の場合もあります。
どちらのアルゴリズムを使用するかは、1) 衝突耐性と2) 署名作成のためのシングルパスインターフェースのどちらの特性を重視するかによって決まります。衝突耐性とは、ハッシュ関数の衝突計算が可能である場合でも、EdDSAが安全であることを意味します。シングルパスインターフェースとは、署名作成に入力メッセージに対する1回のパスのみが必要であることを意味します。PureEdDSAでは、入力に対して2回のパスが必要です。既存の多くのAPI、プロトコル、および環境では、デジタル署名アルゴリズムは入力に対して1回のパスのみで済むと想定されており、それ以外のものをサポートするにはAPIや帯域幅の制約がある場合があります。
署名アルゴリズムの選択に関わらず、ほとんどの署名用途ではシングルパス検証は不可能であることに注意してください。これは、ほとんどの場合、署名が検証されるまでメッセージを処理できず、メッセージ全体を検証する必要があるためです。
このドキュメントでは、HashEdDSAバリアントEd25519phおよびEd448ph、およびPureEdDSAバリアントEd25519およびEd448を生成するパラメータを指定します。
5. EdDSAインスタンス
このセクションでは、PureEdDSAおよびHashEdDSAの各変種(およびEd25519スキームのコンテキスト拡張)について、edwards25519曲線およびedwards448曲線の一般的なEdDSAアルゴリズムをインスタンス化します。したがって、5つの異なるパラメータセットについて説明します。
5.1. Ed25519ph、Ed25519ctx、および Ed25519
Ed25519 は、以下の方法で EdDSA インスタンス化されます。
table:表1 Ed25519のパラメータ
パラメータ edwards25519 例
p RFC 7748 edwards25519のp (例: 2^255 - 19) RFC 7748 p b 256
GF(p)の符号化 255-bit リトルエンディアン符号化の {0, 1, ... p-1}
H(x) SHA-512(dom2(phflag,context)||x) RFC 6234
c 3
edwards25519の2を底とする対数(cofactor) RFC 7748 cofactor
n 254
d 例 -121665/121666 = 370957059346694393431380835087545651895421138798432
19016388785533085940283555 RFC 7748 d
a -1
B (X(P),Y(P)) RFC 7748 (X(P),Y(P))
(151122213495354007725011514095885315114540126930418572060
46113283949847762202, 4631683569492647816942839400347
5163141307993866256225615783033603165251855960)
L 2^252+27742317777372353535851937790883648493 RFC 7748 order
PH(x) x
Ed25519の場合、dom2(f,c)は空文字列です。phflagの値は無関係です。context(存在する場合)は空でなければなりません。これにより、スキームは以前に公開されたEd25519スキームと完全に同一になります。
Ed25519ctx の場合、phflag=0 です。context入力は空であってはなりません。
Ed25519ph の場合、phflag=1 で、PH は SHA512 です。つまり、入力は Ed25519 で署名される前に SHA-512 でハッシュ化されます。
contextの値は署名者と検証者によって設定され(最大 255 オクテット、デフォルトは空文字列ですが、Ed25519 の場合はcontextを持つことができません)、検証が成功するにはオクテットごとに一致する必要があります。
使用される曲線は、座標変換の下で Curve25519 CURVE25519 と同等です。つまり、離散対数問題の難しさは Curve25519 と同じです。 5.1.1. 剰余演算 モジュロ演算 モジュラー演算 Modular Arithmetic $ p = 2^{255} - 19 を法とする演算を効率的かつ安全に実装する方法については、Curve25519 CURVE25519 を参照してください。p を法とする逆元演算については、恒等式 $ x^{-1} = x^{p-2} (\mod p) を使用することを推奨します。ゼロを反転することは決して行ってはなりません。なぜなら、ゼロを反転すると無効な入力が要求され、その場合は事前に検出されるか、計算エラーとなるからです。 点のデコード(point decoding)、つまり「解凍」には、p を法とする平方根が必要です。これは、Tonelli-Shanks アルゴリズム、または p = 5 (mod 8) の特殊なケースを用いて計算できます。a の平方根を求めるには、まず候補となる根 $ x = a^{((p+3)/8)} (\mod p) を計算します。この場合、以下の 3 つのケースが考えられます。
$ x^2 = a (\mod p)。この場合、x は平方根です。
$ x^2 = -a (\mod p)。すると、$ 2^{((p-1)/4)} * x は平方根になります。
a は p を法とした平方根ではありません。
5.1.2. エンコード Encoding
すべての値はオクテット文字列としてエンコードされ、整数はリトルエンディアン方式でエンコードされます。つまり、32オクテット文字列 h $ h[0],...h[31] は、整数 $ h[0] + 2^8 * h[1] + ... + 2^{248} * h[31] を表します。
0 <= x,y < p の範囲の座標を持つ曲線点 (x,y) は、次のようにエンコードされます。まず、y座標を32オクテットのリトルエンディアン文字列としてエンコードします。最後のオクテットの最上位ビットは常に0です。点のエンコードを作成するには、x座標の最下位ビットを最後のオクテットの最上位ビットにコピーします。
5.1.3 デコード Decoding
32オクテットの文字列として与えられた点のデコードは、もう少し複雑です。
1. まず、文字列をリトルエンディアン表現の整数として解釈します。この数値のビット255はx座標の最下位ビットであり、この値をx_0とします。このビットをクリアするだけでy座標が復元されます。結果の値がp以上であれば、デコードは失敗します。
2. x座標を復元するには、曲線方程式から$ x^2 = (y^2 - 1) / (d y^2 + 1) (\mod p)が成り立ちます。分母は常にmod pで非ゼロです。$ u = y^2 - 1、v = d y^2 + 1とします。(u/v)の平方根を計算するには、まず候補根$ x = (u/v)^{(p+3)/8}を計算します。これは、v の逆元と平方根の両方に単一の剰余べき乗法を使用する次のトリックで実現できます。
$ x = (u/v)^{(p+3)/8} = u(u v)^{(p-5)/8} (\mod p)
3. ここでも、3つのケースがあります。
1. $ v x^2 = u (\mod p) の場合、x は平方根です。
2. $ v x^2 = -u (\mod p) の場合、 x <-- $ x * 2^{(p-1)/4} と設定します。これは平方根です。
3. それ以外の場合、p を法とする平方根は存在しないため、デコードは失敗します。
4. 最後に、x_0 ビットを使用して正しい平方根を選択します。x = 0 かつ x_0 = 1 の場合、デコードは失敗します。それ以外の場合、x_0 != x mod 2 の場合、x <-- p - x と設定します。デコードされた点 (x,y) を返します。
5.1.4. ポイント加算 Point Addition
点の加算には、以下の方法が推奨されます。点 (x,y) は、拡張同次座標 (X, Y, Z, T) で表され、x = X/Z、y = Y/Z、x * y = T/Z となります。
中立点は (0,1) です。これは、Z が 0 以外の場合、拡張同次座標 (0, Z, Z, 0) と等価です。
A = (Y1-X1)*(Y2-X2)
B = (Y1+X1)*(Y2+X2)
C = T1*2*d*T2
D = Z1*2*Z2
E = B-A
F = D-C
G = D+C
H = B+A
X3 = E*F
Y3 = G*H
T3 = E*H
Z3 = F*G
点の倍算、(x3,y3) = (x1,y1)+(x1,y1) については、上記の式において等しい点を単に代入するだけで済みます(完全性のため、このような代入は有効です)。こうすることで、4回の乗算が平方根になることが分かります。しかし、Edwards-revisited のセクション3.3およびEFD-TWISTED-DBLで説明されている公式を用いることで、いくつかの小さな演算を省略できます。 A = X1^2
B = Y1^2
C = 2*Z1^2
H = A+B
E = H-(X1+Y1)^2
G = A-B
F = C+G
X3 = E*F
Y3 = G*H
T3 = E*H
Z3 = F*G
5.1.5. 鍵生成 Key Generation
秘密鍵は、暗号的に安全な32オクテット(256ビット、bに相当)のランダムデータです。ランダム性に関する議論はRFC4086を参照してください。 32バイトの公開鍵は、以下の手順で生成されます。
1. 32バイトの秘密鍵をSHA-512でハッシュし、ダイジェストを64オクテットの大きなバッファ(hと表記)に格納します。公開鍵の生成には、下位32バイトのみが使用されます。
2. バッファの刈り込み:最初のオクテットの下位3ビットをクリアし、最後のオクテットの最上位ビットをクリアし、最後のオクテットの上位から2番目のビットをセットします。
3. バッファをリトルエンディアン整数として解釈し、秘密スカラーsを作成します。固定基数のスカラー乗算[s]Bを実行します。
4. 公開鍵Aは、点[s]Bの符号化です。まず、y座標(0 <= y < pの範囲)を32オクテットのリトルエンディアン文字列としてエンコードします。最終オクテットの最上位ビットは常に0です。点[s]Bのエンコードを作成するには、x座標の最下位ビットを最終オクテットの最上位ビットにコピーします。その結果が公開鍵です。
5.1.6. 署名 Sign
署名手順への入力は、秘密鍵、32オクテットの文字列、および任意サイズのメッセージMです。Ed25519ctxおよびEd25519phの場合、さらに最大255オクテットのコンテキストCとフラグF(Ed25519ctxの場合は0、Ed25519phの場合は1)が存在します。
1. 32オクテットの秘密鍵をSHA-512を用いてハッシュします。hを結果のダイジェストとします。前のセクションで説明したように、ダイジェストの前半と対応する公開鍵Aから秘密スカラーsを構築します。prefixをハッシュダイジェストの後半h[32],...,h[63]とします。
2. SHA-512(dom2(F, C) || prefix || PH(M))を計算します。ここで、Mは署名するメッセージです。 64オクテットのダイジェストをリトルエンディアンの整数rとして解釈する。
3. 点[r]Bを計算する。効率を上げるため、まずrをBの群位数Lを法として約分する。この点の符号化を文字列Rとする。
4. SHA512(dom2(F, C) || R || A || PH(M)) を計算し、64オクテットのダイジェストをリトルエンディアン整数 k として解釈する。
5. S = (r + k * s) mod L を計算する。効率を上げるため、まず k を法として減算する。
6. R (32オクテット) と S のリトルエンディアンエンコード (32オクテット。最終オクテットの最上位3ビットは常に0) を連結した署名を作成する。
5.1.7 検証 Verify
1. 公開鍵Aを用いてメッセージMの署名を検証する。FはEd25519ctxの場合は0、Ed25519phの場合は1であり、Ed25519ctxまたはEd25519phが使用されている場合はコンテキストCとする。まず、署名を32オクテットの2つの部分に分割する。前半Rを点R'としてデコードし、後半を0 <= S < Lの範囲の整数Sとしてデコードする。公開鍵Aを点A'としてデコードする。いずれかのデコードが失敗した場合(Sが範囲外の場合を含む)、署名は無効である。
2. SHA512(dom2(F, C) || R || A || PH(M))を計算し、64オクテットのダイジェストをリトルエンディアンの整数kとして解釈する。
3. 群方程式[8][S]B = [8]R' + [8][k]A'を確認する。代わりに [S]B = R' + [k]A' をチェックすれば十分ですが、必須ではありません。
5.2. Ed448ph と Ed448
Ed448は 以下の方法で EdDSA インスタンス化されます。
table:Ed448のパラメータ
パラメータ 値 RFC 7748
p edwards448のp (例, 2^448 - 2^224 - 1) p
b 456
GF(p)の符号化 455-bit リトルエンディアン符号化の {0, 1, ..., p-1}
H(x) SHAKE256(dom4(phflag,context)||x, 114)
phflag 0
c edwards448の2を底とする対数(cofactor) (例 2) cofactor
n 447
d edwards448 の d (例 -39081) d
a 1
B (例 (224580 (X(P),Y(P))
04029592430018760433409989603624678964163256413424612
54616869504154674060329090291928693579532825780320751
46446173674602635247710, 2988192100784814926760179304
43930673437544040154080242095928241372331506189835876
003536878655418784733982303233503462500531545062832660))
L 2^446 - 138180668098951153520073867485154268803366924
74882178609894547503885 order
PH(x) x (例 恒等関数)
Ed448ph も同様ですが、PH が SHAKE256(x, 64) で phflag が 1 です。つまり、入力は署名前にハッシュ定数を変更した Ed448 でハッシュ化されます。
contextの値は署名者と検証者によって設定され(最大 255 オクテット、デフォルトは空文字列)、検証が成功するにはオクテット毎に一致する必要があります。
この曲線は、基点を変更した Ed448-Goldilocks と同等であり、離散対数の難しさは維持されます。
5.2.1. モジュラー演算 Modular Arithmetic
$ p = 2^{448} - 2^{224} - 1 を法とする演算を効率的かつ安全に実装する方法については、ED448 を参照してください。p を法とする逆元については、恒等式 $ x^{-1} = x^{p-2} (\mod p) を使用することが推奨されます。ゼロの反転は、無効な入力が必要となるため、事前に検出されるか、計算エラーとなるため、決して行ってはなりません。 点のデコード、つまり「解凍」には、p を法とする平方根が必要です。これは、まず候補となる平方根 $ x = a ^ {(p+1)/4} (\mod p) を計算し、次に $ x^2 = a であるかどうかを調べることで計算できます。もしそうであれば、x は a の平方根です。そうでなければ、a は平方根を持ちません。
5.2.2. エンコード
すべての値はオクテット文字列としてエンコードされ、整数はリトルエンディアン方式でエンコードされます。つまり、57オクテット文字列 h h[0],...h[56] は、整数 h[0] + 2^8 * h[1] + ... + 2^448 * h[56] を表します。
0 <= x,y < p の範囲の座標を持つ曲線点 (x,y) は、次のようにエンコードされます。まず、y座標を57オクテットのリトルエンディアン文字列としてエンコードします。最後のオクテットは常に0です。点のエンコードを作成するには、x座標の最下位ビットを最後のオクテットの最上位ビットにコピーします。
5.2.3. デコード
57オクテットの文字列として与えられた点のデコードは、もう少し複雑です。
1. まず、文字列をリトルエンディアン表現の整数として解釈します。この数値のビット455はx座標の最下位ビットであり、この値をx_0とします。このビットをクリアするだけでy座標が復元されます。結果の値がp以上であれば、デコードは失敗します。
2. x座標を復元するには、曲線方程式から$ x^2 = (y^2 - 1) / (d y^2 - 1) (\mod p)が成り立ちます。分母は常にmod pで0以外になります。$ u = y^2 - 1、$ v = d y^2 - 1とします。(u/v)の平方根を計算するには、まず候補根$ x = (u/v)^{(p+1)/4}を計算します。これは、v の逆関数と平方根の両方に単一の剰余乗法を使用するという、次のトリックを使うことで実現できます。
$ x = (u/v)^{(p+1)/4} = u (u v)^{(p-3)/4} (\mod p)
3. $ v * x^2 = u の場合、復元された x 座標は x です。それ以外の場合、平方根は存在しないため、デコードは失敗します。
4. 最後に、x_0 ビットを使って正しい平方根を選択します。x = 0 かつ x_0 = 1 の場合、デコードは失敗します。それ以外の場合、x_0 != x mod 2 の場合、x <-- p - x に設定します。デコードされた点 (x,y) を返します。
5.2.4. 点の加算
点の加算には、以下の方法が推奨されます。点 (x, y) は射影座標 (X, Y, Z) で表され、x = X/Z、y = Y/Z となります。
中立点は (0, 1) です。これは、Z が 0 でない任意の点に対して、射影座標 (0, Z, Z) と等価です。
ねじれのないエドワーズ曲線 (つまり a=1) 上の d が正方形でない 2 点の加算式 (x3, y3) = (x1, y1)+(x2, y2) は、Faster-ECC のセクション 4 および EFD-ADD で説明されています。これらの式は完全であり、任意の有効な入力点のペアに対して有効です。 A = Z1*Z2
B = A^2
C = X1*X2
D = Y1*Y2
E = d*C*D
F = B-E
G = B+E
H = (X1+Y1)*(X2+Y2)
X3 = A*F*(H-C-D)
Y3 = A*G*(D-C)
Z3 = F*G
ここでも、他の曲線と同様に、4つの乗算を平方根に置き換えることで、倍加の式を得ることができます。ただし、これは最適とは程遠いものです。Faster-ECCのセクション4とEFD-DBLで説明されている以下の式は、複数の乗算を省略します。 B = (X1+Y1)^2
C = X1^2
D = Y1^2
E = C+D
H = Z1^2
J = E-2*H
X3 = (B-E)*J
Y3 = E*(C-D)
Z3 = E*J
5.2.5. 鍵生成
秘密鍵は、暗号論的に安全なランダムデータからなる57オクテット(456ビット、bに相当)です。ランダム性に関する議論はRFC4086を参照してください。 57バイトの公開鍵は、以下の手順で生成されます。
1. 57バイトの秘密鍵をSHAKE256(x, 114)を用いてハッシュし、ダイジェストを114オクテットの大きなバッファ(hと表記)に格納します。公開鍵の生成には、下位57バイトのみが使用されます。
2. バッファのプルーニング:最初のオクテットの最下位2ビットをクリアし、最後のオクテットの8ビットすべてをクリアし、最後から2番目のオクテットの最上位ビットをセットします。
3. バッファをリトルエンディアン整数として解釈し、秘密スカラーsを生成します。既知基数ポイントのスカラー乗算[s]Bを実行します。
4. 公開鍵Aは点[s]Bのエンコードです。まず、y座標(0 <= y < pの範囲)を57オクテットのリトルエンディアン文字列としてエンコードします。最終オクテットの最上位ビットは常に0です。点[s]Bのエンコードを作成するには、x座標の最下位ビットを最終オクテットの最上位ビットにコピーします。その結果が公開鍵です。
5.2.6. 署名 Sign
署名手続きへの入力は、秘密鍵、57オクテットの文字列、フラグF(Ed448の場合は0、Ed448phの場合は1)、最大255オクテットのコンテキストC、および任意サイズのメッセージMである。
1. SHAKE256(x, 114)を用いて、57オクテットの秘密鍵をハッシュする。得られたダイジェストをhとする。前の節で述べたように、ダイジェストの前半部分と対応する公開鍵Aから秘密スカラーsを構築する。prefixをハッシュダイジェストの後半部分h[57],...,h[113]とする。
2. SHAKE256(dom4(F, C) || prefix || PH(M), 114) を計算します。ここで、M は署名するメッセージ、F は Ed448ph の場合は 1、Ed448 の場合は 0、C は使用するコンテキストです。114 オクテットのダイジェストをリトルエンディアンの整数 r として解釈します。
3. 点 [r]B を計算します。効率を上げるため、まず r を B の群位数 L を法として縮約します。この点のエンコードを文字列 R とします。
4. SHAKE256(dom4(F, C) || R || A || PH(M), 114) を計算し、114 オクテットのダイジェストをリトルエンディアンの整数 k として解釈します。
5. S = (r + k * s) mod L を計算します。効率を上げるため、まず k を法として L を法として縮約します。
6. R (57 オクテット) と S のリトルエンディアン符号化 (57 オクテット、最後のオクテットの最上位 10 ビットは常に 0) を連結した署名を作成します。
5.2.7. 検証 Verify
1. コンテキスト C と公開鍵 A を用いてメッセージ M の署名を検証する。F は Ed448 の場合は 0、Ed448ph の場合は 1 とする。まず、署名を 57 オクテットの 2 つの部分に分割する。前半を点 R として、後半を範囲 0 <= s < L の整数 S としてデコードする。公開鍵 A を点 A' としてデコードする。いずれかのデコードが失敗した場合(S が範囲外の場合を含む)、署名は無効である。
2. SHAKE256(dom4(F, C) || R || A || PH(M), 114) を計算し、114 オクテットのダイジェストをリトルエンディアンの整数 k として解釈する。
3. 群方程式 [4][S]B = [4]R + [4][k]A' を確認する。[S]B = R + [k]A' を確認することで十分であるが、必須ではない。
6. Ed25519 Python による実装例
本節の残りの部分では、Ed25519 を Python (バージョン 3.2 以降) で実装する方法を例として説明します。完全な実装については付録 A を、テストベクトルで実行するためのテストドライバについては付録 B を参照してください。
このコードは、すべての入力に対して正しいことが証明されておらず、サイドチャネル攻撃に対する防御力も備えていないため、本番環境での使用を想定したものではありません。実装者が独自の実装を行う際に役立つよう、アルゴリズムを説明することを目的としています。
まず、必要な準備事項をいくつか説明します。
code:code
import hashlib
def sha512(s):
return hashlib.sha512(s).digest()
# Base field Z_p
p = 2**255 - 19
def modp_inv(x):
return pow(x, p-2, p)
# 曲線定数 Curve constant
d = -121665 * modp_inv(121666) % p
# Group order
q = 2**252 + 27742317777372353535851937790883648493
def sha512_modq(s):
return int.from_bytes(sha512(s), "little") % q
## 次にポイント操作を実行する関数が続きます。 Then follows functions to perform point operations.
# Points are represented as tuples (X, Y, Z, T) of extended
# coordinates, with x = X/Z, y = Y/Z, x*y = T/Z
# 点は拡張座標の組(X、Y、Z、T)として表され、
# x = X/Z、y = Y/Z、x*y = T/Zとなります。
def point_add(P, Q):
A, B = (P1-P0) * (Q1-Q0) % p, (P1+P0) * (Q1+Q0) % p; C, D = 2 * P3 * Q3 * d % p, 2 * P2 * Q2 % p; E, F, G, H = B-A, D-C, D+C, B+A;
return (E*F, G*H, F*G, E*H);
# Computes Q = s * Q
def point_mul(s, P):
Q = (0, 1, 1, 0) # Neutral element
while s > 0:
if s & 1:
Q = point_add(Q, P)
P = point_add(P, P)
s >>= 1
return Q
def point_equal(P, Q):
# x1 / z1 == x2 / z2 <==> x1 * z2 == x2 * z1
if (P0 * Q2 - Q0 * P2) % p != 0: return False
if (P1 * Q2 - Q1 * P2) % p != 0: return False
return True
## Now follows functions for point compression.
# Square root of -1
modp_sqrt_m1 = pow(2, (p-1) // 4, p)
# Compute corresponding x-coordinate, with low bit corresponding to
# sign, or return None on failure
def recover_x(y, sign):
if y >= p:
return None
x2 = (y*y-1) * modp_inv(d*y*y+1)
if x2 == 0:
if sign:
return None
else:
return 0
# Compute square root of x2
x = pow(x2, (p+3) // 8, p)
if (x*x - x2) % p != 0:
x = x * modp_sqrt_m1 % p
if (x*x - x2) % p != 0:
return None
if (x & 1) != sign:
x = p - x
return x
# Base point
g_y = 4 * modp_inv(5) % p
g_x = recover_x(g_y, 0)
G = (g_x, g_y, 1, g_x * g_y % p)
def point_compress(P):
return int.to_bytes(y | ((x & 1) << 255), 32, "little")
def point_decompress(s):
if len(s) != 32:
raise Exception("Invalid input length for decompression")
y = int.from_bytes(s, "little")
sign = y >> 255
y &= (1 << 255) - 1
x = recover_x(y, sign)
if x is None:
return None
else:
return (x, y, 1, x*y % p)
## These are functions for manipulating the private key.
def secret_expand(secret):
if len(secret) != 32:
raise Exception("Bad size of private key")
h = sha512(secret)
a = int.from_bytes(h:32, "little") a &= (1 << 254) - 8
a |= (1 << 254)
def secret_to_public(secret):
(a, dummy) = secret_expand(secret)
return point_compress(point_mul(a, G))
## The signature function works as below.
def sign(secret, msg):
a, prefix = secret_expand(secret)
A = point_compress(point_mul(a, G))
r = sha512_modq(prefix + msg)
R = point_mul(r, G)
Rs = point_compress(R)
h = sha512_modq(Rs + A + msg)
s = (r + h * a) % q
return Rs + int.to_bytes(s, 32, "little")
## And finally the verification function.
def verify(public, msg, signature):
if len(public) != 32:
raise Exception("Bad public key length")
if len(signature) != 64:
raise Exception("Bad signature length")
A = point_decompress(public)
if not A:
return False
R = point_decompress(Rs)
if not R:
return False
s = int.from_bytes(signature32:, "little") if s >= q: return False
h = sha512_modq(Rs + public + msg)
sB = point_mul(s, G)
hA = point_mul(h, A)
return point_equal(sB, point_add(R, hA))
7. テストベクトル
このセクションには、Ed25519ph、Ed25519ctx、Ed448ph、Ed25519、およびEd448のテストベクトルが含まれています。
各セクションには、一連のテストベクトルが含まれています。オクテットは16進数でエンコードされ、読みやすさのために空白が挿入されています。Ed25519、Ed25519ctx、およびEd25519phの秘密鍵と公開鍵は32オクテット、署名は64オクテットです。Ed448およびEd448phの秘密鍵と公開鍵は57オクテット、署名は114オクテットです。メッセージの長さは任意です。コンテキストが空でない場合、1~255オクテットで指定されます。
7.1. Ed25519 のテストベクトル
(略)
付録A. Ed25519/Ed448 Pythonライブラリ
以下は、Pythonで記述されたEd25519/Ed448の実装例です。バージョン3.2以上が必要です。
注: このコードは本番環境向けではありません。すべての入力に対して正しい結果を生成しますが、処理速度が遅く、サイドチャネル攻撃の回避策も備えていません。
(略)
付録B. ライブラリドライバー
以下は、上記のライブラリを使用して、対話型使用または自己チェックのための計算を実行するコマンドラインツールです。
(略)
謝辞
EdDSAとEd25519は、Daniel J. Bernstein、Niels Duif、Tanja Lange、Peter Schwabe、Bo-Yin Yangによる論文で最初に説明されました。Ed448曲線はMike Hamburgによるものです。
この文書の初期ドラフト版は、Niels Moellerが共著しました。
この文書に対するフィードバックは、Werner Koch、Damien Miller、Bob Bradley、Franck Rondepierre、Alexey Melnikov、Kenny Paterson、Robert Edmondsからいただきました。
Ed25519のテストベクトルは、Bob Bradleyによって3つの異なる実装(TweetNaClに基づく実装1つとSUPERCOPのコードに基づく実装2つ)を用いて二重チェックされました。
---- RFC 訳