Module: ECDSA

Defined in:
lib/ecdsa/ext/sign_verify.rb,
lib/ecdsa/ext.rb,
lib/ecdsa/ext/point.rb,
lib/ecdsa/ext/version.rb,
lib/ecdsa/ext/abstract_point.rb,
lib/ecdsa/ext/jacobian_point.rb,
lib/ecdsa/ext/projective_point.rb

Overview

A monkey patch to allow signature generation and verification of existing ECDSA with Jacobian coordinates.

Defined Under Namespace

Modules: Ext Classes: Point

Class Method Summary collapse

Class Method Details

.check_signature!(public_key, digest, signature) ⇒ Object



35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
# File 'lib/ecdsa/ext/sign_verify.rb', line 35

def self.check_signature!(public_key, digest, signature)
  group = public_key.group
  point_field = PrimeField.new(group.order)

  # Step 1: r and s must be in the range [1, n-1].
  unless point_field.include?(signature.r)
    raise InvalidSignatureError, "Invalid signature: r is not in the field."
  end
  unless point_field.include?(signature.s)
    raise InvalidSignatureError, "Invalid signature: s is not in the field."
  end
  if signature.r.zero?
    raise InvalidSignatureError, "Invalid signature: r is zero."
  end
  if signature.s.zero?
    raise InvalidSignatureError, "Invalid signature: s is zero."
  end

  # Step 2 was already performed when the digest of the message was computed.

  # Step 3: Convert octet string to number and take leftmost bits.
  e = normalize_digest(digest, group.bit_length)

  # Step 4
  s_inverted = point_field.inverse(signature.s)
  u1 = point_field.mod(e * s_inverted)
  u2 = point_field.mod(signature.r * s_inverted)

  # Step 5
  r =
    (group.generator.to_jacobian * u1 + public_key.to_jacobian * u2).to_affine
  if r.infinity?
    raise InvalidSignatureError, "Invalid signature: r is infinity in step 5."
  end

  # Steps 6 and 7
  v = point_field.mod r.x

  # Step 8
  if v != signature.r
    raise InvalidSignatureError, "Invalid signature: v does not equal r."
  end

  true
end

.sign(group, private_key, digest, temporary_key) ⇒ Object



5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# File 'lib/ecdsa/ext/sign_verify.rb', line 5

def self.sign(group, private_key, digest, temporary_key)
  # Second part of step 1: Select ephemeral elliptic curve key pair
  # temporary_key was already selected for us by the caller
  # Pad the scalar with the group order so that its bit length is fixed,
  # mitigating a timing leak of the bit length of temporary_key.
  # Since (k + i * n)G = kG, this does not change the result.
  k = temporary_key + group.order
  k += group.order if k.bit_length == group.order.bit_length
  r_point = (group.generator.to_jacobian * k).to_affine

  # Steps 2 and 3
  point_field = PrimeField.new(group.order)
  r = point_field.mod(r_point.x)
  return nil if r.zero?

  # Step 4, calculating the hash, was already performed by the caller.

  # Step 5
  e = normalize_digest(digest, group.bit_length)

  # Step 6
  s =
    point_field.mod(
      point_field.inverse(temporary_key) * (e + r * private_key)
    )
  return nil if s.zero?

  Signature.new r, s
end