lib/tapyrus/secp256k1/native.rb in tapyrus-0.2.2 vs lib/tapyrus/secp256k1/native.rb in tapyrus-0.2.3
- old
+ new
@@ -48,10 +48,12 @@
attach_function(:secp256k1_ecdsa_signature_serialize_der, [:pointer, :pointer, :pointer, :pointer], :int)
attach_function(:secp256k1_ec_pubkey_parse, [:pointer, :pointer, :pointer, :size_t], :int)
attach_function(:secp256k1_ecdsa_signature_parse_der, [:pointer, :pointer, :pointer, :size_t], :int)
attach_function(:secp256k1_ecdsa_signature_normalize, [:pointer, :pointer, :pointer], :int)
attach_function(:secp256k1_ecdsa_verify, [:pointer, :pointer, :pointer, :pointer], :int)
+ attach_function(:secp256k1_schnorr_sign, [:pointer, :pointer, :pointer, :pointer, :pointer, :pointer], :int)
+ attach_function(:secp256k1_schnorr_verify, [:pointer, :pointer, :pointer, :pointer], :int)
end
def with_context(flags: (SECP256K1_CONTEXT_VERIFY | SECP256K1_CONTEXT_SIGN))
init
begin
@@ -98,12 +100,73 @@
# sign data.
# @param [String] data a data to be signed with binary format
# @param [String] privkey a private key using sign
# @param [String] extra_entropy a extra entropy for rfc6979
# @return [String] signature data with binary format
- def sign_data(data, privkey, extra_entropy)
+ 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 signature.
+ # @param[String] data a data.
+ # @param [String] sig signature data with binary format
+ # @param [String] pub_key a public key using verify.
+ 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
+
+ # # validate whether this is a valid public key (more expensive than IsValid())
+ # @param [String] pub_key public key with hex format.
+ # @param [Boolean] allow_hybrid whether support hybrid public key.
+ # @return [Boolean] If valid public key return true, otherwise false.
+ 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
+
+ private
+
+ def generate_pubkey_in_context(context, privkey, compressed: true)
+ internal_pubkey = FFI::MemoryPointer.new(:uchar, 64)
+ result = secp256k1_ec_pubkey_create(context, internal_pubkey, privkey.htb)
+ raise 'error creating pubkey' unless result
+
+ pubkey = FFI::MemoryPointer.new(:uchar, 65)
+ pubkey_len = FFI::MemoryPointer.new(:uint64)
+ result = if compressed
+ pubkey_len.put_uint64(0, 33)
+ secp256k1_ec_pubkey_serialize(context, pubkey, pubkey_len, internal_pubkey, SECP256K1_EC_COMPRESSED)
+ else
+ pubkey_len.put_uint64(0, 65)
+ secp256k1_ec_pubkey_serialize(context, pubkey, pubkey_len, internal_pubkey, SECP256K1_EC_UNCOMPRESSED)
+ end
+ raise 'error serialize pubkey' unless result || pubkey_len.read_uint64 > 0
+ pubkey.read_string(pubkey_len.read_uint64).bth
+ end
+
+ def sign_ecdsa(data, privkey, extra_entropy)
+ with_context do |context|
secret = FFI::MemoryPointer.new(:uchar, privkey.htb.bytesize).put_bytes(0, privkey.htb)
raise 'priv_key invalid' unless secp256k1_ec_seckey_verify(context, secret)
internal_signature = FFI::MemoryPointer.new(:uchar, 64)
msg32 = FFI::MemoryPointer.new(:uchar, 32).put_bytes(0, data)
@@ -124,12 +187,24 @@
signature.read_string(signature_len.read_uint64)
end
end
- def verify_sig(data, sig, pub_key)
+ def sign_schnorr(data, privkey)
with_context do |context|
+ secret = FFI::MemoryPointer.new(:uchar, privkey.htb.bytesize).put_bytes(0, privkey.htb)
+ raise 'priv_key invalid' unless secp256k1_ec_seckey_verify(context, secret)
+
+ signature = FFI::MemoryPointer.new(:uchar, 64)
+ msg32 = FFI::MemoryPointer.new(:uchar, 32).put_bytes(0, data)
+ raise 'Failed to generate schnorr signature.' unless secp256k1_schnorr_sign(context, signature, msg32, secret, nil, nil) == 1
+ signature.read_string
+ end
+ end
+
+ def verify_ecdsa(data, sig, pub_key)
+ with_context do |context|
return false if data.bytesize == 0
pubkey = FFI::MemoryPointer.new(:uchar, pub_key.htb.bytesize).put_bytes(0, pub_key.htb)
internal_pubkey = FFI::MemoryPointer.new(:uchar, 64)
result = secp256k1_ec_pubkey_parse(context, internal_pubkey, pubkey, pubkey.size)
@@ -148,27 +223,25 @@
result == 1
end
end
- private
+ def verify_schnorr(data, sig, pub_key)
+ with_context do |context|
+ return false if data.bytesize == 0
+ pubkey = FFI::MemoryPointer.new(:uchar, pub_key.htb.bytesize).put_bytes(0, pub_key.htb)
+ internal_pubkey = FFI::MemoryPointer.new(:uchar, 64)
+ result = secp256k1_ec_pubkey_parse(context, internal_pubkey, pubkey, pubkey.size)
+ return false unless result
- def generate_pubkey_in_context(context, privkey, compressed: true)
- internal_pubkey = FFI::MemoryPointer.new(:uchar, 64)
- result = secp256k1_ec_pubkey_create(context, internal_pubkey, privkey.htb)
- raise 'error creating pubkey' unless result
+ signature = FFI::MemoryPointer.new(:uchar, sig.bytesize).put_bytes(0, sig)
- pubkey = FFI::MemoryPointer.new(:uchar, 65)
- pubkey_len = FFI::MemoryPointer.new(:uint64)
- result = if compressed
- pubkey_len.put_uint64(0, 33)
- secp256k1_ec_pubkey_serialize(context, pubkey, pubkey_len, internal_pubkey, SECP256K1_EC_COMPRESSED)
- else
- pubkey_len.put_uint64(0, 65)
- secp256k1_ec_pubkey_serialize(context, pubkey, pubkey_len, internal_pubkey, SECP256K1_EC_UNCOMPRESSED)
- end
- raise 'error serialize pubkey' unless result || pubkey_len.read_uint64 > 0
- pubkey.read_string(pubkey_len.read_uint64).bth
+ msg32 = FFI::MemoryPointer.new(:uchar, 32).put_bytes(0, data)
+ result = secp256k1_schnorr_verify(context, signature, msg32, internal_pubkey)
+
+ result == 1
+ end
end
+
end
end
end