Module: Secp256k1::Recover

Included in:
Secp256k1
Defined in:
lib/secp256k1/recovery.rb

Overview

Recover module

Examples:

include Secp256k1

sk, _ = generate_key_pair
msg = Digest::SHA256.digest('message')
sig, rec = sign_recoverable(msg, sk)
full_sig = [rec + 0x1b + 4].pack('C') + [sig].pack('H*')
compressed = true
recover_pubkey = target.recover(msg, full_sig, compressed)

Instance Method Summary collapse

Instance Method Details

#recover(data, signature, compressed) ⇒ String

Recover public key from compact signature.

Parameters:

  • data (String)

    The 32-byte message hash assumed to be signed.

  • signature (String)

    The signature with binary format (65 bytes).

  • compressed (Boolean)

    whether compressed public key or not.

Returns:

  • (String)

    Recovered public key with hex format.

Raises:

  • (Secp256k1::Error)

    If recover failed.

  • (ArgumentError)

    If invalid arguments specified.



49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/secp256k1/recovery.rb', line 49

def recover(data, signature, compressed)
  validate_string!("data", data, 32)
  validate_string!("signature", signature, 65)
  signature = hex2bin(signature)
  data = hex2bin(data)
  rec = (signature[0].ord - 0x1b) & 3
  raise ArgumentError, "rec must be between 0 and 3." if rec < 0 || rec > 3

  with_context do |context|
    sig = FFI::MemoryPointer.new(:uchar, 65)
    input = FFI::MemoryPointer.new(:uchar, 64).put_bytes(0, signature[1..-1])
    result = secp256k1_ecdsa_recoverable_signature_parse_compact(context, sig, input, rec)
    raise Error, 'secp256k1_ecdsa_recoverable_signature_parse_compact failed.' unless result == 1

    pubkey = FFI::MemoryPointer.new(:uchar, 64)
    msg = FFI::MemoryPointer.new(:uchar, data.bytesize).put_bytes(0, data)
    result = secp256k1_ecdsa_recover(context, pubkey, sig, msg)
    raise Error, 'secp256k1_ecdsa_recover failed.' unless result == 1

    serialize_pubkey_internal(context, pubkey.read_string(64), compressed)
  end
end

#sign_recoverable(data, private_key) ⇒ Array

Sign data with compact format.

Parameters:

  • data (String)

    The 32-byte message hash being signed.

  • private_key (String)

    a private key using sign with hex format

Returns:

  • (Array)

    Array of signature and recovery id.

Raises:

  • (Secp256k1::Error)

    If recovery failed.

  • (ArgumentError)

    If invalid arguments specified.



20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# File 'lib/secp256k1/recovery.rb', line 20

def sign_recoverable(data, private_key)
  validate_string!("private_key", private_key, 32)
  validate_string!("data", data, 32)
  private_key = hex2bin(private_key)
  data = hex2bin(data)
  with_context do |context|
    sig = FFI::MemoryPointer.new(:uchar, 65)
    hash =FFI::MemoryPointer.new(:uchar, data.bytesize).put_bytes(0, data)
    sec_key = FFI::MemoryPointer.new(:uchar, private_key.bytesize).put_bytes(0, private_key)
    result = secp256k1_ecdsa_sign_recoverable(context, sig, hash, sec_key, nil, nil)
    raise Error, 'secp256k1_ecdsa_sign_recoverable failed.' if result == 0

    output = FFI::MemoryPointer.new(:uchar, 64)
    rec = FFI::MemoryPointer.new(:uint64)
    result = secp256k1_ecdsa_recoverable_signature_serialize_compact(context, output, rec, sig)
    raise Error, 'secp256k1_ecdsa_recoverable_signature_serialize_compact failed.' unless result == 1

    sig = output.read_string(64).unpack1('H*')
    [sig, rec.read(:int)]
  end
end