Class: RingSig::Key

Inherits:
Object
  • Object
show all
Defined in:
lib/ring_sig/key.rb

Overview

Instances of this class represent an ECDSA key.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(private_key: nil, public_key: nil, group: ECDSA::Group::Secp256k1, hash_algorithm: OpenSSL::Digest::SHA256) ⇒ Key

Creates a new instance of RingSig::Key. Must provide either a private_key or a public_key, but not both.

Parameters:

  • private_key (Integer) (defaults to: nil)
  • public_key (ECDSA::Point) (defaults to: nil)
  • group (ECDSA::Group) (defaults to: ECDSA::Group::Secp256k1)
  • hash_algorithm (#digest) (defaults to: OpenSSL::Digest::SHA256)


24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# File 'lib/ring_sig/key.rb', line 24

def initialize(
   private_key:    nil,
   public_key:     nil,
   group:          ECDSA::Group::Secp256k1,
   hash_algorithm: OpenSSL::Digest::SHA256)

  if private_key && public_key
    raise ArgumentError, "Must not provide both private_key and public_key"
  elsif private_key
    raise ArgumentError, "Private key is not an integer" unless private_key.is_a?(Integer)
    raise ArgumentError, "Private key is too small" if private_key < 1
    raise ArgumentError, "Private key is too large" if private_key >= group.order
    @private_key = private_key
    @public_key = group.generator.multiply_by_scalar(private_key)
  elsif public_key
    raise ArgumentError, "Public key is not an ECDSA::Point" unless public_key.is_a?(ECDSA::Point)
    raise ArgumentError, "Public key is not on the group's curve" unless group.include?(public_key)
    @public_key = public_key
  else
    raise ArgumentError, "Must provide either private_key or public_key"
  end

  @group = group
  @hash_algorithm = hash_algorithm
  @hasher = RingSig::Hasher.new(group, hash_algorithm)
end

Instance Attribute Details

#groupECDSA::Group (readonly)

Returns:

  • (ECDSA::Group)


12
13
14
# File 'lib/ring_sig/key.rb', line 12

def group
  @group
end

#hash_algorithm#digest (readonly)

Returns:

  • (#digest)


15
16
17
# File 'lib/ring_sig/key.rb', line 15

def hash_algorithm
  @hash_algorithm
end

#private_keyInteger (readonly)

Returns:

  • (Integer)


6
7
8
# File 'lib/ring_sig/key.rb', line 6

def private_key
  @private_key
end

#public_keyECDSA::Point (readonly)

Returns:



9
10
11
# File 'lib/ring_sig/key.rb', line 9

def public_key
  @public_key
end

Instance Method Details

#drop_private_keyKey

Returns self if this key has no private key. Otherwise, returns a new key with only the public_key component.

Returns:



92
93
94
95
# File 'lib/ring_sig/key.rb', line 92

def drop_private_key
  return self unless private_key
  Key.new(public_key: public_key, group: group, hash_algorithm: hash_algorithm)
end

#key_imageECDSA::Point

Returns the key image.

Returns:



83
84
85
86
# File 'lib/ring_sig/key.rb', line 83

def key_image
  raise ArgumentError "Cannot compute key image without the private key" unless private_key
  @key_image ||= @hasher.hash_point(@public_key) * @private_key
end

#sign(message, foreign_keys) ⇒ Array(Signature, Array<Key>)

Signs a message with this key’s private_key and a set of public foreign keys. The resulting signature can be verified against the ordered set of all public keys used for creating this signature. The signature will also contain a key_image which will be the same for all messages signed with this key.

Parameters:

  • message (String)

    The message to sign.

  • foreign_keys (Array<Key>)

    The foreign keys for the signature.

Returns:

  • (Array(Signature, Array<Key>))

    A pair containing the signature and the set of public keys (in the correct order) for verifying.



61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
# File 'lib/ring_sig/key.rb', line 61

def sign(message, foreign_keys)
  raise ArgumentError "Cannot sign without a private key" unless private_key
  raise ArgumentError "Foreign keys must all have to the same group" unless foreign_keys.all?{|e| e.group == group}
  raise ArgumentError "Foreign keys must all have to the same hash_algorithm" unless foreign_keys.all?{|e| e.hash_algorithm == hash_algorithm}

  message_digest = @hasher.hash_string(message)
  seed = @hasher.hash_array([private_key, message_digest])

  foreign_keys = foreign_keys.map(&:drop_private_key)
  all_keys = @hasher.shuffle([self] + foreign_keys, seed)

  q_array, w_array = generate_q_w(all_keys, seed)
  ll_array, rr_array = generate_ll_rr(all_keys, q_array, w_array)
  challenge = @hasher.hash_array([message_digest] + ll_array + rr_array)
  c_array, r_array = generate_c_r(all_keys, q_array, w_array, challenge)

  public_keys = all_keys.map(&:drop_private_key)

  [RingSig::Signature.new(key_image, c_array, r_array, group: group, hash_algorithm: @hasher.algorithm), public_keys]
end