Class: RingSig::PrivateKey

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

Overview

Instances of this class represent a private ECDSA key.

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(value, opts = {}) ⇒ PrivateKey

Creates a new instance of RingSig::PrivateKey.

Parameters:

  • value (Integer)
  • opts (Hash) (defaults to: {})

Options Hash (opts):

  • :group (ECDSA::Group)
  • :hash_algorithm (#digest)

Raises:

  • (ArgumentError)


26
27
28
29
30
31
32
33
34
35
36
37
38
# File 'lib/ring_sig/private_key.rb', line 26

def initialize(value, opts = {})
  @group = opts.delete(:group) { RingSig.default_group }
  @hash_algorithm = opts.delete(:hash_algorithm) { RingSig.default_hash_algorithm }
  raise ArgumentError, "Unknown opts: #{opts.keys.join(', ')}" unless opts.empty?

  raise ArgumentError, "Value is not an integer" unless value.is_a?(Integer)
  raise ArgumentError, "Value is too small" if value < 1
  raise ArgumentError, "Value is too large" if value >= group.order

  @value = value
  @public_key = PublicKey.new(group.generator.multiply_by_scalar(value), group: group)
  @hasher = Hasher.new(group: group, hash_algorithm: hash_algorithm)
end

Instance Attribute Details

#groupECDSA::Group (readonly)

Returns:

  • (ECDSA::Group)


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

def group
  @group
end

#hash_algorithm#digest (readonly)

Returns:

  • (#digest)


18
19
20
# File 'lib/ring_sig/private_key.rb', line 18

def hash_algorithm
  @hash_algorithm
end

#public_keyPublicKey (readonly)

Returns:



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

def public_key
  @public_key
end

#valueInteger (readonly)

The integer value of this private key. A number between 0 and the group's order (non-inclusive).

Returns:

  • (Integer)


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

def value
  @value
end

Class Method Details

.from_hex(hex_string, opts = {}) ⇒ PrivateKey

Creates a new instance of RingSig::PrivateKey from a hex string.

Parameters:

  • hex_string (String)
  • opts (Hash) (defaults to: {})

Options Hash (opts):

  • :group (ECDSA::Group)
  • :hash_algorithm (#digest)

Returns:

Raises:

  • (ArgumentError)


47
48
49
50
51
52
53
# File 'lib/ring_sig/private_key.rb', line 47

def self.from_hex(hex_string, opts = {})
  group = opts.delete(:group) { RingSig.default_group }
  hash_algorithm = opts.delete(:hash_algorithm) { RingSig.default_hash_algorithm }
  raise ArgumentError, "Unknown opts: #{opts.keys.join(', ')}" unless opts.empty?

  self.from_octet([hex_string].pack('H*'), group: group, hash_algorithm: hash_algorithm)
end

.from_octet(octet_string, opts = {}) ⇒ PrivateKey

Creates a new instance of RingSig::PrivateKey from an octet string.

Parameters:

  • octet_string (String)
  • opts (Hash) (defaults to: {})

Options Hash (opts):

  • :group (ECDSA::Group)
  • :hash_algorithm (#digest)

Returns:

Raises:

  • (ArgumentError)


62
63
64
65
66
67
68
69
# File 'lib/ring_sig/private_key.rb', line 62

def self.from_octet(octet_string, opts = {})
  group = opts.delete(:group) { RingSig.default_group }
  hash_algorithm = opts.delete(:hash_algorithm) { RingSig.default_hash_algorithm }
  raise ArgumentError, "Unknown opts: #{opts.keys.join(', ')}" unless opts.empty?

  value = ECDSA::Format::FieldElementOctetString.decode(octet_string, group.field)
  PrivateKey.new(value, group: group, hash_algorithm: hash_algorithm)
end

Instance Method Details

#==(other) ⇒ Boolean

Returns true if the private keys are equal.

Returns:

  • (Boolean)

    true if the private keys are equal.



127
128
129
130
# File 'lib/ring_sig/private_key.rb', line 127

def ==(other)
  return false unless other.is_a?(PrivateKey)
  value == other.value && group == other.group && hash_algorithm == other.hash_algorithm
end

#key_imageECDSA::Point

Returns the key image.

Returns:

  • (ECDSA::Point)

    the key image.



117
118
119
# File 'lib/ring_sig/private_key.rb', line 117

def key_image
  @key_image ||= @hasher.hash_point(point) * value
end

#pointECDSA::Point

Returns the public key's point.

Returns:

  • (ECDSA::Point)

    the public key's point.



122
123
124
# File 'lib/ring_sig/private_key.rb', line 122

def point
  public_key.point
end

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

Signs a message with this key's private key and a set of foreign public 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<PublicKey>)

    The foreign keys for the signature.

Returns:

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

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



97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
# File 'lib/ring_sig/private_key.rb', line 97

def sign(message, foreign_keys)
  raise ArgumentError "Foreign keys must all have the same group" unless foreign_keys.all?{ |e| e.group == group }

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

  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(&:public_key)
  signature = Signature.new(key_image, c_array, r_array, group: group, hash_algorithm: hash_algorithm)

  [signature, public_keys]
end

#to_hexString

Encodes this private key into an octet string. The encoded data contains only the value. It does not contain the group or hash_algorithm.

Returns:

  • (String)


75
76
77
# File 'lib/ring_sig/private_key.rb', line 75

def to_hex
  to_octet.unpack('H*').first
end

#to_octetString

Encodes this public key into a hex string. The encoded data contains only the value. It does not contain the group or hash_algorithm.

Returns:

  • (String)


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

def to_octet
  ECDSA::Format::FieldElementOctetString.encode(value, group.field)
end