Module: Schnorr::SignToContract

Defined in:
lib/schnorr/sign_to_contract.rb

Constant Summary collapse

GROUP =
ECDSA::Group::Secp256k1

Class Method Summary collapse

Class Method Details

.sign(message, private_key, contract) ⇒ (Schnorr::Signature, ECDSA::Point)

Generate schnorr signature for sign-to-signature.

Parameters:

  • message (String)

    A message to be signed with binary format.

  • private_key (Integer)

    The private key.

  • contract (String)

    A contract information with 32-bytes binary format.

Returns:



12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# File 'lib/schnorr/sign_to_contract.rb', line 12

def sign(message, private_key, contract)
  raise "The message must be a 32-byte array." unless message.bytesize == 32
  raise "private_key is zero or over the curve order." if private_key == 0 || private_key >= GROUP.order
  raise "The contract must be a 32-byte binary string." unless contract.bytesize == 32

  p = GROUP.new_point(private_key)
  k0 = Schnorr.deterministic_nonce(message, private_key)

  k1, r = tweak(k0, contract)

  q = GROUP.new_point(k1)
  k = ECDSA::PrimeField.jacobi(q.y, GROUP.field.prime) == 1 ? k1 : GROUP.order - k1

  e = Schnorr.create_challenge(q.x, p, message)

  [Schnorr::Signature.new(q.x, (k + e * private_key) % GROUP.order), r]
end

.tweak(k, contract) ⇒ Object



30
31
32
33
34
35
36
37
# File 'lib/schnorr/sign_to_contract.rb', line 30

def tweak(k, contract)
  r = GROUP.new_point(k)
  rx = ECDSA::Format::IntegerOctetString.encode(r.x, GROUP.byte_length)
  h = Tapyrus.sha256(rx + contract)
  k1 = (k + h.bth.to_i(16)) % GROUP.order
  raise "Creation of signature failed. k + h(R || c) is zero" if k1.zero?
  [k1, r]
end

.valid_contract?(r, signature, contract) ⇒ Boolean

Validate contract

Parameters:

Returns:

  • (Boolean)

    true if commitment for contract is valid, otherwise false



44
45
46
47
48
49
# File 'lib/schnorr/sign_to_contract.rb', line 44

def valid_contract?(r, signature, contract)
  rx = ECDSA::Format::IntegerOctetString.encode(r.x, GROUP.byte_length)
  commitment = Tapyrus.sha256(rx + contract).bth.to_i(16) % GROUP.order
  point = r + GROUP.generator.multiply_by_scalar(commitment)
  signature.r == point.x
end