Class: PqcRails::Sig
- Inherits:
-
Object
- Object
- PqcRails::Sig
- Includes:
- LengthValidation
- Defined in:
- lib/pqc_rails/sig.rb
Overview
liboqsのGeneric SIG(署名)APIをRubyらしく包んだクラス。
使い方:
sig = PqcRails::Sig.new(:ml_dsa_44) # またはliboqsの生の名前 "ML-DSA-44"
keypair = sig.generate_keypair
signature = sig.sign("hello world", keypair.secret_key)
sig.verify("hello world", signature, keypair.public_key) # => true
PqcRails::Kem と同じパターン(open/free によるリソース管理)を踏襲している。
Defined Under Namespace
Classes: Keypair
Instance Attribute Summary collapse
-
#alg_name ⇒ Object
readonly
Returns the value of attribute alg_name.
Class Method Summary collapse
Instance Method Summary collapse
- #free ⇒ Object
-
#generate_keypair ⇒ Keypair
鍵ペアを生成する.
-
#initialize(alg_name) ⇒ Sig
constructor
A new instance of Sig.
- #length_public_key ⇒ Object
- #length_secret_key ⇒ Object
-
#length_signature ⇒ Object
(最大の)署名長。ML-DSAのような一部のアルゴリズムは固定長だが、 アルゴリズムによっては実際の署名長がこれより短くなることがある。.
-
#sign(message, secret_key) ⇒ String
メッセージに署名する.
-
#verify(message, signature, public_key) ⇒ Boolean
署名を検証する.
Constructor Details
#initialize(alg_name) ⇒ Sig
Returns a new instance of Sig.
24 25 26 27 28 29 30 31 32 33 34 35 36 |
# File 'lib/pqc_rails/sig.rb', line 24 def initialize(alg_name) @alg_name = alg_name liboqs_alg_name = Algorithms.resolve_sig_name(alg_name) @sig_ptr = Ffi::Sig.OQS_SIG_new(liboqs_alg_name) if @sig_ptr.null? raise PqcRails::Error, "OQS_SIG_new failed for '#{liboqs_alg_name}'. " \ "liboqsがこのアルゴリズムを有効にしてビルドされているか確認してください。" end @sig = Ffi::Sig::Struct.new(@sig_ptr) @freed = false end |
Instance Attribute Details
#alg_name ⇒ Object (readonly)
Returns the value of attribute alg_name.
22 23 24 |
# File 'lib/pqc_rails/sig.rb', line 22 def alg_name @alg_name end |
Class Method Details
.open(alg_name) ⇒ Object
146 147 148 149 150 151 |
# File 'lib/pqc_rails/sig.rb', line 146 def self.open(alg_name) sig = new(alg_name) yield sig ensure sig&.free end |
Instance Method Details
#free ⇒ Object
139 140 141 142 143 144 |
# File 'lib/pqc_rails/sig.rb', line 139 def free return if @freed Ffi::Sig.OQS_SIG_free(@sig_ptr) @freed = true end |
#generate_keypair ⇒ Keypair
鍵ペアを生成する
47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
# File 'lib/pqc_rails/sig.rb', line 47 def generate_keypair ensure_not_freed! public_key = FFI::MemoryPointer.new(:uint8, length_public_key) secret_key = FFI::MemoryPointer.new(:uint8, length_secret_key) status = Ffi::Sig.OQS_SIG_keypair(@sig_ptr, public_key, secret_key) raise PqcRails::Error, "OQS_SIG_keypair failed (status=#{status})" unless status.zero? Keypair.new( public_key.read_bytes(length_public_key), secret_key.read_bytes(length_secret_key) ) end |
#length_public_key ⇒ Object
38 |
# File 'lib/pqc_rails/sig.rb', line 38 def length_public_key = @sig[:length_public_key] |
#length_secret_key ⇒ Object
39 |
# File 'lib/pqc_rails/sig.rb', line 39 def length_secret_key = @sig[:length_secret_key] |
#length_signature ⇒ Object
(最大の)署名長。ML-DSAのような一部のアルゴリズムは固定長だが、 アルゴリズムによっては実際の署名長がこれより短くなることがある。
43 |
# File 'lib/pqc_rails/sig.rb', line 43 def length_signature = @sig[:length_signature] |
#sign(message, secret_key) ⇒ String
メッセージに署名する
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 |
# File 'lib/pqc_rails/sig.rb', line 66 def sign(, secret_key) ensure_not_freed! validate_length!(secret_key, length_secret_key, "secret_key") = FFI::MemoryPointer.new(:uint8, .bytesize) .put_bytes(0, ) secret_key_ptr = FFI::MemoryPointer.new(:uint8, secret_key.bytesize) secret_key_ptr.put_bytes(0, secret_key) # signatureバッファは「最大長」で確保しておく。 # 実際に書き込まれた長さは signature_len_ptr 経由で後から読み取る。 signature_ptr = FFI::MemoryPointer.new(:uint8, length_signature) # OQS_SIG_signの第3引数(signature_len)は size_t* の出力引数。 # FFI::MemoryPointer.new(:size_t, 1) で size_t 1個分の領域を確保し、 # 関数呼び出し後に read_uint64 (64bit環境でのsize_t) で読み出す。 signature_len_ptr = FFI::MemoryPointer.new(:size_t, 1) status = Ffi::Sig.OQS_SIG_sign( @sig_ptr, signature_ptr, signature_len_ptr, , .bytesize, secret_key_ptr ) raise PqcRails::Error, "OQS_SIG_sign failed (status=#{status})" unless status.zero? actual_signature_len = signature_len_ptr.read(:size_t) signature_ptr.read_bytes(actual_signature_len) end |
#verify(message, signature, public_key) ⇒ Boolean
署名を検証する
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 |
# File 'lib/pqc_rails/sig.rb', line 104 def verify(, signature, public_key) ensure_not_freed! validate_length!(public_key, length_public_key, "public_key") # FIPS 204 3.6.3 (Public-Key and Signature Length Checks) は、 # 検証実装がσ(署名)の長さを規格上の長さと照合し、異なればfalseを返すことを要求している。 # length_signatureは最大長のため、超過した時点でliboqsを呼ばずにfalseを返す # (verifyの契約上、不正な入力は例外ではなく検証失敗として扱う。上のpublic_keyチェックとは # 非対称だが、public_keyは通常呼び出し側が管理する信頼済みの値である一方、 # signatureは検証対象そのもの=攻撃者制御下にありうる値のため、扱いを分けている)。 return false if signature.bytesize > length_signature = FFI::MemoryPointer.new(:uint8, .bytesize) .put_bytes(0, ) signature_ptr = FFI::MemoryPointer.new(:uint8, signature.bytesize) signature_ptr.put_bytes(0, signature) public_key_ptr = FFI::MemoryPointer.new(:uint8, public_key.bytesize) public_key_ptr.put_bytes(0, public_key) status = Ffi::Sig.OQS_SIG_verify( @sig_ptr, , .bytesize, signature_ptr, signature.bytesize, public_key_ptr ) # OQS_SIG_verifyは「検証失敗」も含めてOQS_ERRORを返す設計。 # つまりここでのstatusはエラー(例外送出)ではなく、検証結果そのものとして扱う。 status.zero? end |