Module: Tapyrus::Secp256k1::Native

Extended by:
Native
Includes:
FFI::Library
Included in:
Native
Defined in:
lib/tapyrus/secp256k1/native.rb

Overview

binding for secp256k1 (github.com/chaintope/tapyrus-core/tree/v0.4.0/src/secp256k1) tag: v0.4.0 this is not included by default, to enable set shared object path to ENV for linux, ENV = ‘/usr/local/lib/libsecp256k1.so’ for mac,

Constant Summary collapse

SECP256K1_FLAGS_TYPE_MASK =
((1 << 8) - 1)
SECP256K1_FLAGS_TYPE_CONTEXT =
(1 << 0)
SECP256K1_FLAGS_TYPE_COMPRESSION =
(1 << 1)
SECP256K1_FLAGS_BIT_CONTEXT_VERIFY =
(1 << 8)
SECP256K1_FLAGS_BIT_CONTEXT_SIGN =
(1 << 9)
SECP256K1_FLAGS_BIT_COMPRESSION =
(1 << 8)
SECP256K1_CONTEXT_VERIFY =

Flags to pass to secp256k1_context_create.

(SECP256K1_FLAGS_TYPE_CONTEXT | SECP256K1_FLAGS_BIT_CONTEXT_VERIFY)
SECP256K1_CONTEXT_SIGN =
(SECP256K1_FLAGS_TYPE_CONTEXT | SECP256K1_FLAGS_BIT_CONTEXT_SIGN)
SECP256K1_EC_COMPRESSED =

Flag to pass to secp256k1_ec_pubkey_serialize and secp256k1_ec_privkey_export.

(SECP256K1_FLAGS_TYPE_COMPRESSION | SECP256K1_FLAGS_BIT_COMPRESSION)
SECP256K1_EC_UNCOMPRESSED =
(SECP256K1_FLAGS_TYPE_COMPRESSION)

Class Method Summary collapse

Class Method Details

.generate_key(compressed: true) ⇒ Object

generate tapyrus key object



88
89
90
91
# File 'lib/tapyrus/secp256k1/native.rb', line 88

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



73
74
75
76
77
78
79
80
81
82
83
84
85
# File 'lib/tapyrus/secp256k1/native.rb', line 73

def generate_key_pair(compressed: true)
  with_context do |context|
    ret, tries, max = 0, 0, 20
    while ret != 1
      raise "secp256k1_ec_seckey_verify in generate_key_pair failed." if tries >= max
      tries += 1
      priv_key = FFI::MemoryPointer.new(:uchar, 32).put_bytes(0, SecureRandom.random_bytes(32))
      ret = secp256k1_ec_seckey_verify(context, priv_key)
    end
    private_key = priv_key.read_string(32).bth
    [private_key, generate_pubkey_in_context(context, private_key, compressed: compressed)]
  end
end

.generate_pubkey(priv_key, compressed: true) ⇒ Object



93
94
95
# File 'lib/tapyrus/secp256k1/native.rb', line 93

def generate_pubkey(priv_key, compressed: true)
  with_context { |context| generate_pubkey_in_context(context, priv_key, compressed: compressed) }
end

.initObject



33
34
35
36
37
# File 'lib/tapyrus/secp256k1/native.rb', line 33

def init
  raise "secp256k1 library dose not found." unless File.exist?(ENV["SECP256K1_LIB_PATH"])
  ffi_lib(ENV["SECP256K1_LIB_PATH"])
  load_functions
end

.load_functionsObject



39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# File 'lib/tapyrus/secp256k1/native.rb', line 39

def load_functions
  attach_function(:secp256k1_context_create, [:uint], :pointer)
  attach_function(:secp256k1_context_destroy, [:pointer], :void)
  attach_function(:secp256k1_context_randomize, %i[pointer pointer], :int)
  attach_function(:secp256k1_ec_pubkey_create, %i[pointer pointer pointer], :int)
  attach_function(:secp256k1_ec_seckey_verify, %i[pointer pointer], :int)
  attach_function(:secp256k1_ecdsa_sign, %i[pointer pointer pointer pointer pointer pointer], :int)
  attach_function(:secp256k1_ec_pubkey_serialize, %i[pointer pointer pointer pointer uint], :int)
  attach_function(:secp256k1_ecdsa_signature_serialize_der, %i[pointer pointer pointer pointer], :int)
  attach_function(:secp256k1_ec_pubkey_parse, %i[pointer pointer pointer size_t], :int)
  attach_function(:secp256k1_ecdsa_signature_parse_der, %i[pointer pointer pointer size_t], :int)
  attach_function(:secp256k1_ecdsa_signature_normalize, %i[pointer pointer pointer], :int)
  attach_function(:secp256k1_ecdsa_verify, %i[pointer pointer pointer pointer], :int)
  attach_function(:secp256k1_schnorr_sign, %i[pointer pointer pointer pointer pointer pointer], :int)
  attach_function(:secp256k1_schnorr_verify, %i[pointer pointer pointer pointer], :int)
end

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

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

Parameters:

  • pub_key (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.



132
133
134
135
136
137
138
139
140
141
# File 'lib/tapyrus/secp256k1/native.rb', line 132

def parse_ec_pubkey?(pub_key, allow_hybrid = false)
  pub_key = pub_key.htb
  return false if !allow_hybrid && ![0x02, 0x03, 0x04].include?(pub_key[0].ord)
  with_context do |context|
    pubkey = FFI::MemoryPointer.new(:uchar, pub_key.bytesize).put_bytes(0, pub_key)
    internal_pubkey = FFI::MemoryPointer.new(:uchar, 64)
    result = secp256k1_ec_pubkey_parse(context, internal_pubkey, pubkey, pub_key.bytesize)
    result == 1
  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

  • extra_entropy (String)

    a extra entropy for rfc6979

Returns:

  • (String)

    signature data with binary format



102
103
104
105
106
107
108
109
110
111
# File 'lib/tapyrus/secp256k1/native.rb', line 102

def sign_data(data, privkey, extra_entropy, algo: :ecdsa)
  case algo
  when :ecdsa
    sign_ecdsa(data, privkey, extra_entropy)
  when :schnorr
    sign_schnorr(data, privkey)
  else
    nil
  end
end

.verify_sig(data, sig, pub_key, algo: :ecdsa) ⇒ Object

verify signature. @param data a data.

Parameters:

  • sig (String)

    signature data with binary format

  • pub_key (String)

    a public key using verify.



117
118
119
120
121
122
123
124
125
126
# File 'lib/tapyrus/secp256k1/native.rb', line 117

def verify_sig(data, sig, pub_key, algo: :ecdsa)
  case algo
  when :ecdsa
    verify_ecdsa(data, sig, pub_key)
  when :schnorr
    verify_schnorr(data, sig, pub_key)
  else
    false
  end
end

.with_context(flags: (SECP256K1_CONTEXT_VERIFY | SECP256K1_CONTEXT_SIGN)) ⇒ Object



56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/tapyrus/secp256k1/native.rb', line 56

def with_context(flags: (SECP256K1_CONTEXT_VERIFY | SECP256K1_CONTEXT_SIGN))
  init
  begin
    context = secp256k1_context_create(flags)
    ret, tries, max = 0, 0, 20
    while ret != 1
      raise "secp256k1_context_randomize failed." if tries >= max
      tries += 1
      ret = secp256k1_context_randomize(context, FFI::MemoryPointer.from_string(SecureRandom.random_bytes(32)))
    end
    yield(context) if block_given?
  ensure
    secp256k1_context_destroy(context)
  end
end