Class: Secp256k1::MuSig::Session

Inherits:
Object
  • Object
show all
Includes:
Secp256k1
Defined in:
lib/secp256k1/musig/session.rb

Constant Summary

Constants included from Secp256k1

CONTEXT_SIGN, CONTEXT_VERIFY, EC_COMPRESSED, EC_UNCOMPRESSED, ELL_SWIFT_KEY_SIZE, FLAGS_BIT_COMPRESSION, FLAGS_BIT_CONTEXT_SIGN, FLAGS_BIT_CONTEXT_VERIFY, FLAGS_TYPE_COMPRESSION, FLAGS_TYPE_CONTEXT, FLAGS_TYPE_MASK, VERSION, X_ONLY_PUBKEY_SIZE

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Secp256k1

#create_keypair, #generate_key_pair, #generate_pubkey, #parse_ec_pubkey?, #sign_ecdsa, #valid_xonly_pubkey?, #verify_ecdsa, #with_context

Methods included from Secp256k1::MuSig

#aggregate_musig_nonce, #aggregate_pubkey, #generate_musig_nonce, #generate_musig_session_id

Methods included from EllSwift

#ellswift_create, #ellswift_decode, #ellswift_ecdh_xonly

Methods included from SchnorrSig

#sign_schnorr, #verify_schnorr

Methods included from Recover

#recover, #sign_recoverable

Methods included from C

ellswift_xdh_hash_function_bip324

Constructor Details

#initialize(key_agg_ctx, agg_nonce, msg) ⇒ Session

Create signing session.

Parameters:

  • key_agg_ctx (Secp256k1::MuSig::KeyAggContext)

    The key aggregation context.

  • agg_nonce (String)

    An aggregated public nonce.

  • msg (String)

    The message to be signed.

Raises:



16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# File 'lib/secp256k1/musig/session.rb', line 16

def initialize(key_agg_ctx, agg_nonce, msg)
  raise ArgumentError, 'key_agg_ctx must be KeyAggContext.' unless key_agg_ctx.is_a?(KeyAggContext)
  validate_string!('msg', msg, 32)
  validate_string!('agg_nonce', agg_nonce, 66)
  agg_nonce = hex2bin(agg_nonce)
  msg = hex2bin(msg)
  with_context do |context|
    @session = FFI::MemoryPointer.new(:uchar, 133)
    agg66 = FFI::MemoryPointer.new(:uchar, 66).put_bytes(0, agg_nonce)
    agg_ptr = FFI::MemoryPointer.new(:uchar, 132)
    if secp256k1_musig_aggnonce_parse(context, agg_ptr, agg66) == 0
      raise Error, "secp256k1_musig_aggnonce_parse failed."
    end
    msg_ptr = FFI::MemoryPointer.new(:uchar, 32).put_bytes(0, msg)
    if secp256k1_musig_nonce_process(context, @session, agg_ptr, msg_ptr, key_agg_ctx.pointer) == 0
      raise Error, "secp256k1_musig_nonce_process arguments invalid."
    end
  end
  @agg_nonce = agg_nonce.unpack1('H*')
  @msg = msg.unpack1('H*')
  @key_agg_ctx = key_agg_ctx
end

Instance Attribute Details

#agg_nonceObject (readonly)

Returns the value of attribute agg_nonce.



7
8
9
# File 'lib/secp256k1/musig/session.rb', line 7

def agg_nonce
  @agg_nonce
end

#key_agg_ctxObject (readonly)

Returns the value of attribute key_agg_ctx.



6
7
8
# File 'lib/secp256k1/musig/session.rb', line 6

def key_agg_ctx
  @key_agg_ctx
end

#msgObject (readonly)

Returns the value of attribute msg.



8
9
10
# File 'lib/secp256k1/musig/session.rb', line 8

def msg
  @msg
end

#sessionObject (readonly)

Returns the value of attribute session.



5
6
7
# File 'lib/secp256k1/musig/session.rb', line 5

def session
  @session
end

Instance Method Details

#aggregate_partial_sigs(partial_sigs) ⇒ String

Aggregates partial signatures

Parameters:

  • partial_sigs (Array)

    Array of partial signatures.

Returns:

  • (String)

    An aggregated signature.

Raises:



97
98
99
100
101
102
103
104
105
106
107
108
109
# File 'lib/secp256k1/musig/session.rb', line 97

def aggregate_partial_sigs(partial_sigs)
  raise ArgumentError, "partial_sigs must be Array." unless partial_sigs.is_a?(Array)
  raise ArgumentError, "partial_sigs must not be empty." if partial_sigs.empty?
  with_context do |context|
    sigs_ptr = FFI::MemoryPointer.new(:pointer, partial_sigs.length)
    sigs_ptr.write_array_of_pointer(partial_sigs.map{|partial_sig| parse_partial_sig(context, partial_sig)})
    sig64 = FFI::MemoryPointer.new(:uchar, 64)
    if secp256k1_musig_partial_sig_agg(context, sig64, session, sigs_ptr, partial_sigs.length) == 0
      raise Error, "secp256k1_musig_partial_sig_agg arguments invalid."
    end
    sig64.read_string(64).unpack1('H*')
  end
end

#partial_sign(sec_nonce, private_key) ⇒ String

Produces a partial signature for a given key pair and secret nonce.

Parameters:

  • sec_nonce (String)

    The secret nonce to sign the message.

  • private_key (String)

    The private key to sign the message.

Returns:

  • (String)

    A partial signature.

Raises:



45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# File 'lib/secp256k1/musig/session.rb', line 45

def partial_sign(sec_nonce, private_key)
  raise ArgumentError, 'key_agg_ctx must be KeyAggContext.' unless key_agg_ctx.is_a?(KeyAggContext)
  validate_string!('sec_nonce', sec_nonce, 132)
  validate_string!('private_key', private_key, 32)
  with_context do |context|
    partial_sig = FFI::MemoryPointer.new(:uchar, 36)
    sec_nonce_ptr = FFI::MemoryPointer.new(:uchar, 132).put_bytes(0, hex2bin(sec_nonce))
    private_key_ptr = FFI::MemoryPointer.new(:uchar, 32).put_bytes(0, hex2bin(private_key))
    key_pair = FFI::MemoryPointer.new(:uchar, 86)
    if secp256k1_keypair_create(context, key_pair, private_key_ptr) == 0
      raise Error, "secp256k1_keypair_create invalid private_key."
    end
    if secp256k1_musig_partial_sign(
      context, partial_sig, sec_nonce_ptr, key_pair, key_agg_ctx.cache.pointer, session) == 0
      raise Error, "secp256k1_musig_partial_sign arguments invalid or sec_nonce has already been used for signing."
    end
    out32 = FFI::MemoryPointer.new(:uchar, 32)
    secp256k1_musig_partial_sig_serialize(context, out32, partial_sig)
    out32.read_string(32).unpack1('H*')
  end
end

#verify_partial_sig(partial_sig, pub_nonce, public_key) ⇒ Boolean

Checks that an individual partial signature verifies.

Parameters:

  • partial_sig (String)

    The partial signature to verify, sent by the signer associated with pub_nonce and public_key.

  • pub_nonce (String)

    The public nonce of the signer in the signing session.

  • public_key (String)

    The public key of the signer in the signing session.

Returns:

  • (Boolean)

    The verification result.

Raises:



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

def verify_partial_sig(partial_sig, pub_nonce, public_key)
  validate_string!('partial_sig', partial_sig, 32)
  validate_string!('pub_nonce', pub_nonce, 66)
  validate_string!('public_key', public_key, 33)
  with_context do |context|
    sig_ptr = parse_partial_sig(context, partial_sig)
    public_key = FFI::MemoryPointer.new(:uchar, 33).put_bytes(0, hex2bin(public_key))
    pubkey_ptr = FFI::MemoryPointer.new(:uchar, 64)
    raise Error, "pubkey is invalid." unless secp256k1_ec_pubkey_parse(context, pubkey_ptr, public_key, 33) == 1
    pub_nonce = FFI::MemoryPointer.new(:uchar, 66).put_bytes(0, hex2bin(pub_nonce))
    nonce_ptr = FFI::MemoryPointer.new(:uchar, 132)
    if secp256k1_musig_pubnonce_parse(context, nonce_ptr, pub_nonce) == 0
      raise Error, "secp256k1_musig_pubnonce_parse failed."
    end
    secp256k1_musig_partial_sig_verify(context, sig_ptr, nonce_ptr, pubkey_ptr, key_agg_ctx.pointer, session) == 1
  end
end