Class: PqcRails::Kem

Inherits:
Object
  • Object
show all
Includes:
LengthValidation
Defined in:
lib/pqc_rails/kem.rb

Overview

liboqsのGeneric KEM APIをRubyらしく包んだクラス。

使い方:

kem = PqcRails::Kem.new(:ml_kem_512) # またはliboqsの生の名前 "ML-KEM-512"
keypair = kem.generate_keypair
encap   = kem.encapsulate(keypair.public_key)
shared  = kem.decapsulate(encap.ciphertext, keypair.secret_key)
shared == encap.shared_secret # => true

kem.free を呼ぶか、ブロック形式(PqcRails::Kem.open)を使うことで Cレベルのメモリを確実に解放できる。

Defined Under Namespace

Classes: Encapsulation, Keypair

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(alg_name) ⇒ Kem

Returns a new instance of Kem.



27
28
29
30
31
32
33
34
35
36
37
38
39
# File 'lib/pqc_rails/kem.rb', line 27

def initialize(alg_name)
  @alg_name = alg_name
  liboqs_alg_name = Algorithms.resolve_kem_name(alg_name)
  @kem_ptr = Ffi::Kem.OQS_KEM_new(liboqs_alg_name)
  if @kem_ptr.null?
    raise PqcRails::Error,
          "OQS_KEM_new failed for '#{liboqs_alg_name}'. " \
          "liboqsがこのアルゴリズムを有効にしてビルドされているか確認してください。"
  end

  @kem = Ffi::Kem::Struct.new(@kem_ptr)
  @freed = false
end

Instance Attribute Details

#alg_nameObject (readonly)

Returns the value of attribute alg_name.



25
26
27
# File 'lib/pqc_rails/kem.rb', line 25

def alg_name
  @alg_name
end

Class Method Details

.open(alg_name) ⇒ Object



103
104
105
106
107
108
# File 'lib/pqc_rails/kem.rb', line 103

def self.open(alg_name)
  kem = new(alg_name)
  yield kem
ensure
  kem&.free
end

Instance Method Details

#decapsulate(ciphertext, secret_key) ⇒ Object

Raises:



79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
# File 'lib/pqc_rails/kem.rb', line 79

def decapsulate(ciphertext, secret_key)
  ensure_not_freed!
  validate_length!(ciphertext, length_ciphertext, "ciphertext")
  validate_length!(secret_key, length_secret_key, "secret_key")

  shared_secret = FFI::MemoryPointer.new(:uint8, length_shared_secret)
  ct_ptr        = FFI::MemoryPointer.new(:uint8, ciphertext.bytesize)
  ct_ptr.put_bytes(0, ciphertext)
  sk_ptr        = FFI::MemoryPointer.new(:uint8, secret_key.bytesize)
  sk_ptr.put_bytes(0, secret_key)

  status = Ffi::Kem.OQS_KEM_decaps(@kem_ptr, shared_secret, ct_ptr, sk_ptr)
  raise PqcRails::Error, "OQS_KEM_decaps failed (status=#{status})" unless status.zero?

  shared_secret.read_bytes(length_shared_secret)
end

#encapsulate(public_key) ⇒ Object

Raises:



61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/pqc_rails/kem.rb', line 61

def encapsulate(public_key)
  ensure_not_freed!
  validate_length!(public_key, length_public_key, "public_key")

  ciphertext    = FFI::MemoryPointer.new(:uint8, length_ciphertext)
  shared_secret = FFI::MemoryPointer.new(:uint8, length_shared_secret)
  pk_ptr        = FFI::MemoryPointer.new(:uint8, public_key.bytesize)
  pk_ptr.put_bytes(0, public_key)

  status = Ffi::Kem.OQS_KEM_encaps(@kem_ptr, ciphertext, shared_secret, pk_ptr)
  raise PqcRails::Error, "OQS_KEM_encaps failed (status=#{status})" unless status.zero?

  Encapsulation.new(
    ciphertext.read_bytes(length_ciphertext),
    shared_secret.read_bytes(length_shared_secret)
  )
end

#freeObject



96
97
98
99
100
101
# File 'lib/pqc_rails/kem.rb', line 96

def free
  return if @freed

  Ffi::Kem.OQS_KEM_free(@kem_ptr)
  @freed = true
end

#generate_keypairObject

Raises:



46
47
48
49
50
51
52
53
54
55
56
57
58
59
# File 'lib/pqc_rails/kem.rb', line 46

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::Kem.OQS_KEM_keypair(@kem_ptr, public_key, secret_key)
  raise PqcRails::Error, "OQS_KEM_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_ciphertextObject



43
# File 'lib/pqc_rails/kem.rb', line 43

def length_ciphertext    = @kem[:length_ciphertext]

#length_public_keyObject



41
# File 'lib/pqc_rails/kem.rb', line 41

def length_public_key    = @kem[:length_public_key]

#length_secret_keyObject



42
# File 'lib/pqc_rails/kem.rb', line 42

def length_secret_key    = @kem[:length_secret_key]

#length_shared_secretObject



44
# File 'lib/pqc_rails/kem.rb', line 44

def length_shared_secret = @kem[:length_shared_secret]