module Schnorr::MuSig
github.com/ElementsProject/secp256k1-zkp/blob/secp256k1-zkp/src/modules/musig/musig.md
Constants
- TAG
SHA256(“MuSig coefficient”)
Public Instance Methods
Computes MuSig
coefficient SHA256(TAG
|| TAG
|| ell
|| idx
). @param ell (String) a ell with binary format. @param idx (Integer
) an index of public key. @return (Integer
) coefficient value.
# File lib/schnorr/mu_sig.rb, line 37 def coefficient(ell, idx) field = ECDSA::PrimeField.new(ECDSA::Group::Secp256k1.order) field.mod(Digest::SHA256.digest(TAG + TAG + ell + [idx].pack('I*')).unpack('H*').first.to_i(16)) end
Combine the partial signatures to obtain a complete signature. @param combined_nonce (Array) @param signatures (Array) co-signer's signature. @return (Schnorr::Signature
) a combined signature.
# File lib/schnorr/mu_sig.rb, line 73 def partial_sig_combine(combined_nonce, signatures) point_r = ECDSA::Format::PointOctetString.decode(combined_nonce, ECDSA::Group::Secp256k1) field = ECDSA::PrimeField.new(ECDSA::Group::Secp256k1.order) signature = signatures.inject{|sum, s|field.mod(sum + s)} Schnorr::Signature.new(point_r.x, signature) end
Combine public keys. @param public_keys (Array) The set of public keys with binary format. @return (String) a combined public key point with binary format.
# File lib/schnorr/mu_sig.rb, line 23 def pubkey_combine(public_keys, ell: nil) ell = compute_ell(public_keys) unless ell points = public_keys.map.with_index do |p, idx| xi = ECDSA::Format::PointOctetString.decode(p, ECDSA::Group::Secp256k1) xi.multiply_by_scalar(coefficient(ell, idx)) end sum = points.inject(:+) ECDSA::Format::PointOctetString.encode(sum, compression: true) end
Initialize session to signer starts the session. @param session_id (String) if session_id
is nil, generate new one. @param private_key (Integer
) a private key. @param message (String) a message for sign with binary format. @param combined_pubkey (String) combined public key with binary format. @param ell (String) ell with binary format. @param index (Integer
) public key index. @param num_signers (Integer
) the number of signers. @return (Schnorr::MuSig::Session
) session object.
# File lib/schnorr/mu_sig.rb, line 51 def session_initialize(session_id, private_key, message, combined_pubkey, ell, index, num_signers) raise ArgumentError, 'session_id must be 32 bytes.' if session_id && session_id.bytesize != 32 raise ArgumentError, 'message must be 32 bytes.' unless message.bytesize == 32 raise ArgumentError, 'combined_pubkey must be 33 bytes.' unless combined_pubkey.bytesize == 33 raise ArgumentError, 'ell must be 32 bytes.' unless ell.bytesize == 32 secret = ECDSA::Format::IntegerOctetString.encode(private_key, ECDSA::Group::Secp256k1.byte_length) field = ECDSA::PrimeField.new(ECDSA::Group::Secp256k1.order) session = Schnorr::MuSig::Session.new(session_id, num_signers) coefficient = coefficient(ell, index) session.secret_key = field.mod(private_key * coefficient) session.secret_nonce = Digest::SHA256.digest(session.id + message + combined_pubkey + secret).unpack('H*').first.to_i(16) raise ArgumentError, 'secret nonce must be an integer in the ragen 1..n-1' unless field.include?(session.secret_nonce) point_r = ECDSA::Group::Secp256k1.new_point(session.secret_nonce) session.nonce = ECDSA::Format::PointOctetString.encode(point_r, compression: true) session end