genComponents.ts 2.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  1. /**
  2. * """
  3. Generate a full set of fusion components, commitments, keys, and proofs.
  4. count: int
  5. inputs: dict of {(prevout_hash, prevout_n): (pubkey, integer value in sats)}
  6. outputs: list of [(value, addr), (value, addr) ...]
  7. feerate: int (sat/kB)
  8. Returns:
  9. list of InitialCommitment,
  10. list of component original indices (inputs then outputs then blanks),
  11. list of serialized Component,
  12. list of Proof,
  13. list of communication privkey,
  14. Pedersen amount for total, (== excess fee)
  15. Pedersen nonce for total,
  16. """
  17. */
  18. export default (num_blanks, inputs, outputs, feerate) => {
  19. assert num_blanks >= 0
  20. components = []
  21. for (phash, pn), (pubkey, value) in inputs:
  22. fee = component_fee(size_of_input(pubkey), feerate)
  23. comp = pb.Component()
  24. comp.input.prev_txid = bytes.fromhex(phash)[::-1]
  25. comp.input.prev_index = pn
  26. comp.input.pubkey = pubkey
  27. comp.input.amount = value
  28. components.append((comp, +value-fee))
  29. for value, addr in outputs:
  30. script = addr.to_script()
  31. fee = component_fee(size_of_output(script), feerate)
  32. comp = pb.Component()
  33. comp.output.scriptpubkey = script
  34. comp.output.amount = value
  35. components.append((comp, -value-fee))
  36. for _ in range(num_blanks):
  37. comp = pb.Component(blank={})
  38. components.append((comp, 0))
  39. # Generate commitments and (partial) proofs
  40. resultlist = []
  41. sum_nonce = 0
  42. sum_amounts = 0
  43. for cnum, (comp, commitamount) in enumerate(components):
  44. salt = secrets.token_bytes(32)
  45. comp.salt_commitment = sha256(salt)
  46. compser = comp.SerializeToString()
  47. pedersencommitment = Protocol.PEDERSEN.commit(commitamount)
  48. sum_nonce += pedersencommitment.nonce
  49. sum_amounts += commitamount
  50. privkey, pubkeyU, pubkeyC = gen_keypair()
  51. commitment = pb.InitialCommitment()
  52. commitment.salted_component_hash = sha256(salt+compser)
  53. commitment.amount_commitment = pedersencommitment.P_uncompressed
  54. commitment.communication_key = pubkeyC
  55. commitser = commitment.SerializeToString()
  56. proof = pb.Proof()
  57. # proof.component_idx = <to be filled in later>
  58. proof.salt = salt
  59. proof.pedersen_nonce = int(pedersencommitment.nonce).to_bytes(32, 'big')
  60. resultlist.append((commitser, cnum, compser, proof, privkey))
  61. # Sort by the commitment bytestring, in order to forget the original order.
  62. resultlist.sort(key=lambda x:x[0])
  63. sum_nonce = sum_nonce % pedersen.order
  64. pedersen_total_nonce = int(sum_nonce).to_bytes(32, 'big')
  65. return zip(*resultlist), sum_amounts, pedersen_total_nonce
  66. }