Module: Tapyrus::Secp256k1::Ruby

Defined in:
lib/tapyrus/secp256k1/ruby.rb

Overview

secp256 module using ecdsa gem github.com/DavidEGrayson/ruby_ecdsa

Class Method Summary collapse

Class Method Details

.generate_key(compressed: true) ⇒ Object

generate tapyrus key object



18
19
20
21
# File 'lib/tapyrus/secp256k1/ruby.rb', line 18

def generate_key(compressed: true)
  privkey, pubkey = generate_key_pair(compressed: compressed)
  Tapyrus::Key.new(priv_key: privkey, pubkey: pubkey, compressed: compressed)
end

.generate_key_pair(compressed: true) ⇒ Object

generate ec private key and public key



9
10
11
12
13
14
15
# File 'lib/tapyrus/secp256k1/ruby.rb', line 9

def generate_key_pair(compressed: true)
  private_key = 1 + SecureRandom.random_number(GROUP.order - 1)
  public_key = GROUP.generator.multiply_by_scalar(private_key)
  privkey = ECDSA::Format::IntegerOctetString.encode(private_key, 32)
  pubkey = public_key.to_hex(compressed)
  [privkey.bth, pubkey]
end

.generate_pubkey(privkey, compressed: true) ⇒ Object



23
24
25
26
# File 'lib/tapyrus/secp256k1/ruby.rb', line 23

def generate_pubkey(privkey, compressed: true)
  public_key = ECDSA::Group::Secp256k1.generator.multiply_by_scalar(privkey.to_i(16))
  public_key.to_hex(compressed)
end

.parse_ec_pubkey?(pubkey, allow_hybrid = false) ⇒ Boolean

validate whether this is a valid public key (more expensive than IsValid())

Parameters:

  • pubkey (String)

    public key with hex format.

  • allow_hybrid (Boolean) (defaults to: false)

    whether support hybrid public key.

Returns:

  • (Boolean)

    If valid public key return true, otherwise false.



67
68
69
70
71
72
73
74
75
# File 'lib/tapyrus/secp256k1/ruby.rb', line 67

def parse_ec_pubkey?(pubkey, allow_hybrid = false)
  begin
    point =
      ECDSA::Format::PointOctetString.decode(pubkey.htb, ECDSA::Group::Secp256k1, allow_hybrid: allow_hybrid)
    ECDSA::Group::Secp256k1.valid_public_key?(point)
  rescue ECDSA::Format::DecodeError
    false
  end
end

.repack_pubkey(pubkey) ⇒ Object

if pubkey is hybrid public key format, it convert uncompressed format. lists.linuxfoundation.org/pipermail/bitcoin-dev/2012-June/001578.html



79
80
81
82
83
84
85
86
87
88
# File 'lib/tapyrus/secp256k1/ruby.rb', line 79

def repack_pubkey(pubkey)
  p = pubkey.htb
  case p[0]
  when "\x06", "\x07"
    p[0] = "\x04"
    p
  else
    pubkey.htb
  end
end

.sign_data(data, privkey, extra_entropy, algo: :ecdsa) ⇒ String

sign data.

Parameters:

  • data (String)

    a data to be signed with binary format

  • privkey (String)

    a private key using sign

Returns:

  • (String)

    signature data with binary format



32
33
34
35
36
37
38
39
40
41
# File 'lib/tapyrus/secp256k1/ruby.rb', line 32

def sign_data(data, privkey, extra_entropy, algo: :ecdsa)
  case algo
  when :ecdsa
    sign_ecdsa(data, privkey, extra_entropy)
  when :schnorr
    Schnorr.sign(data, privkey.to_i(16)).encode
  else
    nil
  end
end

.sign_ecdsa(data, privkey, extra_entropy) ⇒ Object



90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
# File 'lib/tapyrus/secp256k1/ruby.rb', line 90

def sign_ecdsa(data, privkey, extra_entropy)
  privkey = privkey.htb
  private_key = ECDSA::Format::IntegerOctetString.decode(privkey)
  extra_entropy ||= ""
  nonce = RFC6979.generate_rfc6979_nonce(privkey + data, extra_entropy)

  # port form ecdsa gem.
  r_point = GROUP.new_point(nonce)

  point_field = ECDSA::PrimeField.new(GROUP.order)
  r = point_field.mod(r_point.x)
  return nil if r.zero?

  e = ECDSA.normalize_digest(data, GROUP.bit_length)
  s = point_field.mod(point_field.inverse(nonce) * (e + r * private_key))

  if s > (GROUP.order / 2)
    # convert low-s
    s = GROUP.order - s
  end

  return nil if s.zero?

  signature = ECDSA::Signature.new(r, s).to_der
  public_key = Tapyrus::Key.new(priv_key: privkey.bth).pubkey
  raise "Creation of signature failed." unless Tapyrus::Secp256k1::Ruby.verify_sig(data, signature, public_key)
  signature
end

.verify_ecdsa(digest, sig, pubkey) ⇒ Object



119
120
121
122
123
124
125
126
127
# File 'lib/tapyrus/secp256k1/ruby.rb', line 119

def verify_ecdsa(digest, sig, pubkey)
  begin
    k = ECDSA::Format::PointOctetString.decode(repack_pubkey(pubkey), GROUP)
    signature = ECDSA::Format::SignatureDerString.decode(sig)
    ECDSA.valid_signature?(k, digest, signature)
  rescue Exception
    false
  end
end

.verify_sig(digest, sig, pubkey, algo: :ecdsa) ⇒ Boolean Also known as: valid_sig?

verify signature using public key

Parameters:

  • digest (String)

    a SHA-256 message digest with binary format

  • sig (String)

    a signature for data with binary format

  • pubkey (String)

    a public key corresponding to the private key used for sign

Returns:

  • (Boolean)

    verify result



48
49
50
51
52
53
54
55
56
57
# File 'lib/tapyrus/secp256k1/ruby.rb', line 48

def verify_sig(digest, sig, pubkey, algo: :ecdsa)
  case algo
  when :ecdsa
    verify_ecdsa(digest, sig, pubkey)
  when :schnorr
    Schnorr.valid_sig?(digest, sig, pubkey.htb)
  else
    false
  end
end