Class: ECDSA::Point

Inherits:
Object
  • Object
show all
Defined in:
lib/ecdsa/point.rb

Overview

Instances of this class represent a point on an elliptic curve. The instances hold their ‘x` and `y` coordinates along with a reference to the Group (curve) they belong to.

An instance of this class can also represent the infinity point (the additive identity of the group), in which case ‘x` and `y` are `nil`.

Note: These Point objects are not checked when they are created so they might not actually be on the curve. You can use Group#include? to see if they are on the curve.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(group, *args) ⇒ Point

Creates a new instance of ECDSA::Point. This method is NOT part of the public interface of the ECDSA gem. You should call Group#new_point instead of calling this directly.

Parameters:

  • group (Group)
  • args

    Either the x and y coordinates as integers, or just ‘:infinity` to create the infinity point.



29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# File 'lib/ecdsa/point.rb', line 29

def initialize(group, *args)
  @group = group

  if args == [:infinity]
    @infinity = true
    # leave @x and @y nil
  else
    x, y = args
    raise ArgumentError, "Invalid x: #{x.inspect}" if !x.is_a? Integer
    raise ArgumentError, "Invalid y: #{y.inspect}" if !y.is_a? Integer

    @x = x
    @y = y
  end
end

Instance Attribute Details

#groupGroup (readonly)

Returns the curve that the point is on.

Returns:

  • (Group)

    the curve that the point is on.



14
15
16
# File 'lib/ecdsa/point.rb', line 14

def group
  @group
end

#xInteger or nil (readonly)

Returns the x coordinate, or nil for the infinity point.

Returns:

  • (Integer or nil)

    the x coordinate, or nil for the infinity point.



17
18
19
# File 'lib/ecdsa/point.rb', line 17

def x
  @x
end

#yInteger or nil (readonly)

Returns the y coordinate, or nil for the infinity point.

Returns:

  • (Integer or nil)

    the y coordinate, or nil for the infinity point.



20
21
22
# File 'lib/ecdsa/point.rb', line 20

def y
  @y
end

Instance Method Details

#==(other) ⇒ true or false

Compares this point to another.

Returns:

  • (true or false)

    true if the points are equal



143
144
145
# File 'lib/ecdsa/point.rb', line 143

def ==(other)
  eql?(other)
end

#add_to_point(other) ⇒ Object Also known as: +

Adds this point to another point on the same curve using the standard rules for point addition defined in section 2.2.1 of [SEC1](www.secg.org/collateral/sec1_final.pdf).

Parameters:

Returns:

  • The sum of the two points.



58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/ecdsa/point.rb', line 58

def add_to_point(other)
  check_group! other

  # Assertions:
  # raise "point given (#{point.inspect}) does not belong to #{group.name}" if !group.include?(point)
  # raise "point (#{inspect}) does not belong to #{group.name}" if !group.include?(self)

  # Rules 1 and 2
  return other if infinity?
  return self if other.infinity?

  # Rule 3
  return group.infinity if x == other.x && y == field.mod(-other.y)

  # Rule 4
  if x != other.x
    gamma = field.mod((other.y - y) * field.inverse(other.x - x))
    sum_x = field.mod(gamma * gamma - x - other.x)
    sum_y = field.mod(gamma * (x - sum_x) - y)
    return self.class.new(group, sum_x, sum_y)
  end

  # Rule 5
  return double if self == other

  raise "Failed to add #{inspect} to #{other.inspect}: No addition rules matched."
end

#coordsArray

Returns an array of the coordinates, with ‘x` first and `y` second.

Returns:

  • (Array)


48
49
50
# File 'lib/ecdsa/point.rb', line 48

def coords
  [x, y]
end

#doublePoint

Returns the point added to itself.

This algorithm is defined in [SEC1](www.secg.org/collateral/sec1_final.pdf), Section 2.2.1, Rule 5.

Returns:



104
105
106
107
108
109
110
# File 'lib/ecdsa/point.rb', line 104

def double
  return self if infinity?
  gamma = field.mod((3 * x * x + @group.param_a) * field.inverse(2 * y))
  new_x = field.mod(gamma * gamma - 2 * x)
  new_y = field.mod(gamma * (x - new_x) - y)
  self.class.new(group, new_x, new_y)
end

#eql?(other) ⇒ true or false

Compares this point to another.

Returns:

  • (true or false)

    true if the points are equal



135
136
137
138
# File 'lib/ecdsa/point.rb', line 135

def eql?(other)
  return false if !other.is_a?(Point) || other.group != group
  x == other.x && y == other.y
end

#hashInteger

Returns a hash for this point so it can be stored in hash tables with the expected behavior. Two points that have the same coordinates and are on the same curve are equal, so they should not get separate spots in a hash table.

Returns:

  • (Integer)


153
154
155
# File 'lib/ecdsa/point.rb', line 153

def hash
  [group, x, y].hash
end

#infinity?true or false

Returns true if this instance represents the infinity point (the additive identity of the group).

Returns:

  • (true or false)


161
162
163
# File 'lib/ecdsa/point.rb', line 161

def infinity?
  @infinity == true
end

#inspectString

Returns a string showing the value of the point which is useful for debugging.

Returns:

  • (String)


169
170
171
172
173
174
175
# File 'lib/ecdsa/point.rb', line 169

def inspect
  if infinity?
    '#<%s: %s, infinity>' % [self.class, group.name]
  else
    '#<%s: %s, 0x%x, 0x%x>' % [self.class, group.name, x, y]
  end
end

#multiply_by_scalar(i) ⇒ Point Also known as: *

Returns the point multiplied by a non-negative integer.

Parameters:

  • i (Integer)

Returns:

Raises:

  • (ArgumentError)


116
117
118
119
120
121
122
123
124
125
126
127
# File 'lib/ecdsa/point.rb', line 116

def multiply_by_scalar(i)
  raise ArgumentError, 'Scalar is not an integer.' if !i.is_a?(Integer)
  raise ArgumentError, 'Scalar is negative.' if i < 0
  result = group.infinity
  v = self
  while i > 0
    result = result.add_to_point(v) if i.odd?
    v = v.double
    i >>= 1
  end
  result
end

#negatePoint

Returns the additive inverse of the point.

Returns:



92
93
94
95
# File 'lib/ecdsa/point.rb', line 92

def negate
  return self if infinity?
  self.class.new(group, x, field.mod(-y))
end