Class: Schnorr::MuSig2::SessionContext
- Inherits:
-
Object
- Object
- Schnorr::MuSig2::SessionContext
- Includes:
- Util
- Defined in:
- lib/schnorr/musig2/context/session.rb
Instance Attribute Summary collapse
-
#agg_ctx ⇒ Object
readonly
Returns the value of attribute agg_ctx.
-
#agg_nonce ⇒ Object
readonly
Returns the value of attribute agg_nonce.
-
#b ⇒ Object
readonly
Returns the value of attribute b.
-
#modes ⇒ Object
readonly
Returns the value of attribute modes.
-
#msg ⇒ Object
readonly
Returns the value of attribute msg.
-
#pubkeys ⇒ Object
readonly
Returns the value of attribute pubkeys.
-
#r ⇒ Object
readonly
Returns the value of attribute r.
-
#tweaks ⇒ Object
readonly
Returns the value of attribute tweaks.
-
#used_secnonces ⇒ Object
readonly
Returns the value of attribute used_secnonces.
Instance Method Summary collapse
-
#aggregate_partial_sigs(partial_sigs) ⇒ Schnorr::Signature
Aggregate partial signatures.
-
#e ⇒ Integer
Get message digest.
-
#initialize(agg_nonce, pubkeys, msg, tweaks = [], modes = []) ⇒ SessionContext
constructor
A new instance of SessionContext.
-
#sign(nonce, sk) ⇒ String
Create partial signature.
-
#valid_partial_sig?(partial_sig, pub_nonce, signer_index) ⇒ Boolean
Verify partial signature.
Methods included from Util
#hex2bin, #hex_string?, #string2point
Constructor Details
#initialize(agg_nonce, pubkeys, msg, tweaks = [], modes = []) ⇒ SessionContext
Returns a new instance of SessionContext.
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
# File 'lib/schnorr/musig2/context/session.rb', line 12 def initialize(agg_nonce, pubkeys, msg, tweaks = [], modes = []) @used_secnonces = [] @agg_nonce = hex2bin(agg_nonce) @pubkeys = pubkeys.map do |pubkey| pubkey = hex2bin(pubkey) raise ArgumentError, 'pubkey must be 33 bytes' unless pubkey.bytesize == 33 pubkey end @msg = hex2bin(msg) @tweaks = tweaks @modes = modes @modes.each do |mode| raise ArgumentError, 'mode must be Boolean.' unless [TrueClass, FalseClass].include?(mode.class) end @agg_ctx = MuSig2.aggregate_with_tweaks(@pubkeys, @tweaks, @modes) @b = Schnorr.tagged_hash('MuSig/noncecoef', @agg_nonce + agg_ctx.q.encode(true) + @msg).bti begin r1 = string2point(@agg_nonce[0...33]).to_jacobian r2 = string2point(@agg_nonce[33...66]).to_jacobian rescue ECDSA::Format::DecodeError raise ArgumentError, 'Invalid agg_nonce' end r = (r1 + r2 * @b).to_affine @r = r.infinity? ? GROUP.generator : r end |
Instance Attribute Details
#agg_ctx ⇒ Object (readonly)
Returns the value of attribute agg_ctx.
5 6 7 |
# File 'lib/schnorr/musig2/context/session.rb', line 5 def agg_ctx @agg_ctx end |
#agg_nonce ⇒ Object (readonly)
Returns the value of attribute agg_nonce.
5 6 7 |
# File 'lib/schnorr/musig2/context/session.rb', line 5 def agg_nonce @agg_nonce end |
#b ⇒ Object (readonly)
Returns the value of attribute b.
5 6 7 |
# File 'lib/schnorr/musig2/context/session.rb', line 5 def b @b end |
#modes ⇒ Object (readonly)
Returns the value of attribute modes.
5 6 7 |
# File 'lib/schnorr/musig2/context/session.rb', line 5 def modes @modes end |
#msg ⇒ Object (readonly)
Returns the value of attribute msg.
5 6 7 |
# File 'lib/schnorr/musig2/context/session.rb', line 5 def msg @msg end |
#pubkeys ⇒ Object (readonly)
Returns the value of attribute pubkeys.
5 6 7 |
# File 'lib/schnorr/musig2/context/session.rb', line 5 def pubkeys @pubkeys end |
#r ⇒ Object (readonly)
Returns the value of attribute r.
5 6 7 |
# File 'lib/schnorr/musig2/context/session.rb', line 5 def r @r end |
#tweaks ⇒ Object (readonly)
Returns the value of attribute tweaks.
5 6 7 |
# File 'lib/schnorr/musig2/context/session.rb', line 5 def tweaks @tweaks end |
#used_secnonces ⇒ Object (readonly)
Returns the value of attribute used_secnonces.
5 6 7 |
# File 'lib/schnorr/musig2/context/session.rb', line 5 def used_secnonces @used_secnonces end |
Instance Method Details
#aggregate_partial_sigs(partial_sigs) ⇒ Schnorr::Signature
Aggregate partial signatures.
102 103 104 105 106 107 108 109 110 111 112 |
# File 'lib/schnorr/musig2/context/session.rb', line 102 def aggregate_partial_sigs(partial_sigs) s = 0 partial_sigs.each do |partial_sig| s_i = hex2bin(partial_sig).bti raise ArgumentError, 'Invalid partial sig.' if s_i >= GROUP.order s = (s + s_i) % GROUP.order end g = agg_ctx.q.has_even_y? ? 1 : GROUP.order - 1 s = (s + e * g * agg_ctx.tacc) % GROUP.order Schnorr::Signature.new(r.x, s) end |
#e ⇒ Integer
Get message digest.
40 41 42 |
# File 'lib/schnorr/musig2/context/session.rb', line 40 def e Schnorr.tagged_hash('BIP0340/challenge', r.encode(true) + agg_ctx.q.encode(true) + msg).bti end |
#sign(nonce, sk) ⇒ String
Create partial signature.
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
# File 'lib/schnorr/musig2/context/session.rb', line 48 def sign(nonce, sk) nonce = hex2bin(nonce) raise ArgumentError, 'Same nonce already used.' if used_secnonces.include?(nonce) sk = hex2bin(sk) k1 = nonce[0...32].bti k2 = nonce[32...64].bti raise ArgumentError, 'first nonce value is out of range.' if k1 <= 0 || GROUP.order <= k1 raise ArgumentError, 'second nonce value is out of range.' if k2 <= 0 || GROUP.order <= k2 k1 = r.has_even_y? ? k1 : GROUP.order - k1 k2 = r.has_even_y? ? k2 : GROUP.order - k2 d = sk.bti raise ArgumentError, 'secret key value is out of range.' if d <= 0 || GROUP.order <= d p = (GROUP.generator.to_jacobian * d).to_affine.encode raise ArgumentError, 'Public key does not match nonce_gen argument' unless p == nonce[64...97] a = key_agg_coeff(pubkeys, p) g = agg_ctx.q.has_even_y? ? 1 : GROUP.order - 1 d = (g * agg_ctx.gacc * d) % GROUP.order s = (k1 + b * k2 + e * a * d) % GROUP.order r1 = (GROUP.generator.to_jacobian * k1).to_affine r2 = (GROUP.generator.to_jacobian * k2).to_affine raise ArgumentError, 'R1 can not be infinity.' if r1.infinity? raise ArgumentError, 'R2 can not be infinity.' if r2.infinity? used_secnonces << nonce ECDSA::Format::IntegerOctetString.encode(s, GROUP.byte_length).unpack1('H*') end |
#valid_partial_sig?(partial_sig, pub_nonce, signer_index) ⇒ Boolean
Verify partial signature.
79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 |
# File 'lib/schnorr/musig2/context/session.rb', line 79 def valid_partial_sig?(partial_sig, pub_nonce, signer_index) begin partial_sig = hex2bin(partial_sig) pub_nonce = hex2bin(pub_nonce) s = partial_sig.bti return false if s >= GROUP.order r1 = string2point(pub_nonce[0...33]).to_jacobian r2 = string2point(pub_nonce[33...66]).to_jacobian r_s = (r1 + r2 * b).to_affine r_s = r.has_even_y? ? r_s : r_s.negate pk = string2point(pubkeys[signer_index]) a = key_agg_coeff(pubkeys, pubkeys[signer_index]) g = agg_ctx.q.has_even_y? ? 1 : GROUP.order - 1 g = (g * agg_ctx.gacc) % GROUP.order GROUP.generator.to_jacobian * s == r_s.to_jacobian + pk.to_jacobian * (e * a * g % GROUP.order) rescue ECDSA::Format::DecodeError => e raise ArgumentError, e end end |