Top Level Namespace

Defined Under Namespace

Modules: Cryptos

Constant Summary collapse

EC_Gx =
0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798
EC_Gy =
0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8
EC_p =
0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F
EC_n =
0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141
LOW_S =
0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0

Instance Method Summary collapse

Methods included from Cryptos::Utils::Bytes

#bignum_to_bytes, #bytes_to_bignum

Instance Method Details

#ec_add(ax, ay, bx, by, pn) ⇒ Object



49
50
51
52
53
54
55
56
57
58
59
# File 'lib/cryptos/elliptic_curve.rb', line 49

def ec_add(ax, ay, bx, by, pn)
  return [ax, ay] if bx == 0 && by == 0
  return [bx, by] if ax == 0 && ay == 0
  return ec_double(ax, ay, pn) if ax == bx && ay == by

  i_bax = inverse(ax - bx, pn)
  slope = ((ay - by) * i_bax) % pn
  x = (slope**2 - ax - bx) % pn
  y = (slope*(ax - x) - ay) % pn
  [x, y]
end

#ec_double(px, py, pn) ⇒ Object



42
43
44
45
46
47
48
# File 'lib/cryptos/elliptic_curve.rb', line 42

def ec_double(px, py, pn)
  i_2y = inverse(2 * py, pn)
  slope = (3 * px**2 * i_2y) % pn
  x = (slope**2 - 2 * px) % pn
  y = (slope*(px - x) - py) % pn
  [x, y]
end

#ec_multiply(m, px, py, pn) ⇒ Object



60
61
62
63
64
65
66
67
68
69
# File 'lib/cryptos/elliptic_curve.rb', line 60

def ec_multiply(m, px, py, pn)
  nx, ny = px, py
  qx, qy = 0, 0
  while m > 0
    qx, qy = ec_add qx, qy, nx, ny, pn if m&1 == 1
    nx, ny = ec_double nx, ny, pn
    m >>= 1
  end
  [qx, qy]
end

#ecdsa_sign(private_key, digest, temp_key = nil) ⇒ Object

ECDSA



74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
# File 'lib/cryptos/elliptic_curve.rb', line 74

def ecdsa_sign(private_key, digest, temp_key = nil)
  temp_key ||= Cryptos::PrivateKey.generate.value
  rx, _ry = ec_multiply(temp_key, EC_Gx, EC_Gy, EC_p)
  r = rx % EC_n
  r > 0 || raise('r is zero, try again new temp key')
  i_tk = inverse temp_key, EC_n
  m = bytes_to_bignum digest
  s = (i_tk * (m + r * private_key)) % EC_n
  s > 0 || raise('s is zero, try again new temp key')
  if s > LOW_S
    # https://github.com/bitcoin/bips/blob/master/bip-0062.mediawiki#low-s-values-in-signatures
    # puts 'WARN: s is too big, use low s values'
    s = (EC_n - s) % EC_n
  end
  [r, s]
end

#ecdsa_verify?(px, py, digest, signature) ⇒ Boolean

Returns:

  • (Boolean)


91
92
93
94
95
96
97
98
99
100
101
# File 'lib/cryptos/elliptic_curve.rb', line 91

def ecdsa_verify?(px, py, digest, signature)
  r, s = signature
  i_s = inverse s, EC_n
  m = bytes_to_bignum digest
  u1 = i_s * m % EC_n
  u2 = i_s * r % EC_n
  u1Gx, u1Gy = ec_multiply u1, EC_Gx, EC_Gy, EC_p
  u2Px, u2Py = ec_multiply u2, px, py, EC_p
  rx, _ry = ec_add u1Gx, u1Gy, u2Px, u2Py, EC_p
  r == rx
end

#extended_euclidean_algorithm(a, b) ⇒ Object



24
25
26
27
28
29
30
31
32
33
34
35
# File 'lib/cryptos/elliptic_curve.rb', line 24

def extended_euclidean_algorithm(a, b)
  s, old_s = 0, 1
  t, old_t = 1, 0
  r, old_r = b, a
  while r != 0
    quotient = old_r / r
    old_r, r = r, old_r - quotient * r
    old_s, s = s, old_s - quotient * s
    old_t, t = t, old_t - quotient * t
  end
  [old_r, old_s, old_t]
end

#inverse(n, p) ⇒ Object



36
37
38
39
40
41
# File 'lib/cryptos/elliptic_curve.rb', line 36

def inverse(n, p)
  gcd, x, y = extended_euclidean_algorithm(n, p)
  (n * x + p * y) % p == gcd || raise('invalid gcd')
  gcd == 1 || raise('no multiplicative inverse')
  x % p
end