### Example CET Weight Calculation Source: https://context7.com/discreetlogcontracts/dlcspecs/llms.txt Demonstrates calculating CET weight and virtual bytes using the `calculate_cet_weight` function. Assumes P2WPKH outputs. ```python # Example cet_weight = calculate_cet_weight(22, 22) # P2WPKH outputs print(f"CET weight: {cet_weight}") print(f"CET vbytes: {(cet_weight + 3) // 4}") ``` -------------------------------- ### Binary Numeric Outcome Compression Example Source: https://github.com/discreetlogcontracts/dlcspecs/blob/master/NumericOutcomeCompression.md Example of covering the interval [5677, 8621] in binary using digit prefixes. ```text 0101100010111_, 0101100011____, 01011001______, 0101101_______, 010111________, 011___________, 100000________, 1000010_______, 100001100_____, 10000110100___, 100001101010__, 10000110101100 ``` -------------------------------- ### Calculate Left Inner and Left Prefixes (Maximize Coverage) Source: https://github.com/discreetlogcontracts/dlcspecs/blob/master/MultiOracle.md Computes leftInnerPrefix and leftPrefix for a large primary interval when maximizeCoverage is true. leftInnerPrefix covers [start, start] and leftPrefix covers [start - halfMaxError, start - halfMaxError + width]. ```javascript leftInnerPrefix = numToVec(start, numDigits, maxErrorExp - 1) leftPrefix = numToVec(start - halfMaxError, numDigits, maxErrorExp - 1) ``` -------------------------------- ### Base 10 Numeric Outcome Compression Example Source: https://github.com/discreetlogcontracts/dlcspecs/blob/master/NumericOutcomeCompression.md Example of covering the interval [5677, 8621] in base 10 using digit prefixes where underscores represent ignored digits. ```text 5678, 5679, 568_, 569_, 57__, 58__, 59__, 6_, 7_, 80__, 81__, 82__, 83__, 84__, 85__, 860_, 861_, 8620 ``` -------------------------------- ### Base 10 Interval Grouping Example Source: https://github.com/discreetlogcontracts/dlcspecs/blob/master/NumericOutcomeCompression.md A visual representation of the grouping pattern for the interval [2200, 4999] in base 10. ```text 2201, 2202, 2203, 2204, 2205, 2206, 2207, 2208, 2209, 221_, 222_, 223_, 224_, 225_, 226_, 227_, 228_, 229_, 23__, 24__, 25__, 26__, 27__, 28__, 29__, 3___, 40__, 41__, 42__, 43__, 44__, 45__, 46__, 47__, 48__, 490_, 491_, 492_, 493_, 494_, 495_, 496_, 497_, 498_, 4990, 4991, 4992, 4993, 4994, 4995, 4996, 4997, 4998 ``` -------------------------------- ### Create Oracle Attestation in Python Source: https://context7.com/discreetlogcontracts/dlcspecs/llms.txt Produces an attestation by signing event outcomes with corresponding nonces. ```python def create_oracle_attestation(oracle_private_key, event_id, nonces, outcomes): """ Create oracle attestation with signatures over outcomes For numeric events, outcomes are individual digits For enum events, outcome is the selected string """ signatures = [] for nonce_private, outcome in zip(nonces, outcomes): # Outcome encoded as UTF-8 with NFC normalization outcome_bytes = outcome.encode('utf-8') # Create tagged hash tag = sha256(b"DLC/oracle/attestation/v0").digest() message_hash = sha256(tag + tag + outcome_bytes).digest() # Sign with nonce sig = bip340_sign_with_nonce(oracle_private_key, nonce_private, message_hash) signatures.append(sig) return { "event_id": event_id, "oracle_public_key": get_x_only_pubkey(oracle_private_key), "signatures": signatures, "outcomes": outcomes } # Example: Attest to numeric outcome 12345 in base 10 # Oracle signs: "1", "2", "3", "4", "5" with corresponding nonces attestation = create_oracle_attestation( oracle_key, "btc-usd-2024-01-15", nonces=[n1, n2, n3, n4, n5], outcomes=["1", "2", "3", "4", "5"] ) ``` -------------------------------- ### Compute Adaptor Points in Python Source: https://context7.com/discreetlogcontracts/dlcspecs/llms.txt Calculates adaptor points for CET signing based on oracle public keys, nonces, and outcomes. ```python def compute_adaptor_point_single(oracle_pubkey, nonce, outcome): """ Compute adaptor point for single-digit outcome S = R + H(R || P || m) * P """ outcome_bytes = outcome.encode('utf-8') tag = sha256(b"DLC/oracle/attestation/v0").digest() message_hash = sha256(tag + tag + outcome_bytes).digest() # S = R + H(R || P || m) * P challenge = sha256(nonce + oracle_pubkey + message_hash).digest() challenge_scalar = int.from_bytes(challenge, 'big') % SECP256K1_ORDER adaptor_point = point_add(nonce, point_multiply(oracle_pubkey, challenge_scalar)) return adaptor_point def compute_adaptor_point_multi_digit(oracle_pubkey, nonces, outcomes): """ Compute aggregate adaptor point for numeric outcome Aggregate by point addition: S_total = S_0 + S_1 + ... + S_n """ points = [ compute_adaptor_point_single(oracle_pubkey, nonce, outcome) for nonce, outcome in zip(nonces, outcomes) ] return reduce(point_add, points) # Example: Adaptor point for outcome "42" (digits "4" and "2") adaptor = compute_adaptor_point_multi_digit( oracle_pub, [nonce_tens, nonce_ones], ["4", "2"] ) ``` -------------------------------- ### DLEQ Proving Algorithm Source: https://github.com/discreetlogcontracts/dlcspecs/blob/master/ECDSA-adaptor.md Use this algorithm to generate a proof of discrete logarithm equality. It requires a non-zero scalar witness and three non-zero secp256k1 points. ```plaintext Set a to sample_nonce(tag || X || Y || Z || x) Set A_G to a * G Set A_Y to a * Y Set b to H(X || Y || Z || A_G || A_Y) Set c to a + b * x Set proof to b || c Return proof ``` -------------------------------- ### Compute Middle Grouping Source: https://github.com/discreetlogcontracts/dlcspecs/blob/master/NumericOutcomeCompression.md Generates a middle grouping based on the first unique digit of the start and end of an interval. It iterates from the digit after the start's first digit up to, but not including, the end's first digit. ```scala def middleGrouping( firstDigitStart: Int, // The first unique digit of the interval's start firstDigitEnd: Int): Vector[Vector[Int]] = { // The first unique digit of the interval's end (firstDigitStart + 1).until(firstDigitEnd).toVector.map { firstDigit => // Note that this loop excludes firstDigitEnd Vector(firstDigit) } } ``` -------------------------------- ### Create Oracle Announcement in Python Source: https://context7.com/discreetlogcontracts/dlcspecs/llms.txt Generates a signed announcement committing to event details and nonces using BIP-340 Schnorr signatures. ```python import struct from hashlib import sha256 def create_oracle_announcement(oracle_private_key, oracle_event): """ Create a signed oracle announcement oracle_event structure: - nb_nonces: number of nonces - oracle_nonces: list of x-only public keys (32 bytes each) - event_maturity_epoch: Unix timestamp - event_descriptor: enum or digit_decomposition - event_id: UTF-8 string """ # Serialize oracle_event event_bytes = serialize_oracle_event(oracle_event) # Create tagged hash for signing tag = sha256(b"DLC/oracle/announcement/v0").digest() tagged_hash = sha256(tag + tag + event_bytes).digest() # Sign with BIP-340 Schnorr signature = bip340_sign(oracle_private_key, tagged_hash) return { "announcement_signature": signature, # 64 bytes "oracle_public_key": get_x_only_pubkey(oracle_private_key), # 32 bytes "oracle_event": oracle_event } # Example: Enum event descriptor for weather enum_event = { "type": "enum_event_descriptor", "type_id": 55302, "outcomes": ["sunny", "cloudy", "rainy"] } # Example: Digit decomposition for BTC/USD price numeric_event = { "type": "digit_decomposition_event_descriptor", "type_id": 55306, "base": 2, "is_signed": False, "unit": "dollars", "precision": 0, "nb_digits": 20 # Covers 0 to 1,048,575 } ``` -------------------------------- ### Create P2WSH Funding Output Script Source: https://context7.com/discreetlogcontracts/dlcspecs/llms.txt Generates a P2WSH 2-of-2 multisig script for the funding transaction output. Pubkeys are sorted lexicographically according to BIP-67 to ensure consistent script construction. ```python def create_funding_output_script(offer_funding_pubkey, accept_funding_pubkey): """ Create P2WSH 2-of-2 multisig script Pubkeys sorted lexicographically per BIP-67 """ # Sort pubkeys lexicographically pubkey1, pubkey2 = sorted([offer_funding_pubkey, accept_funding_pubkey]) # Build witness script: 2 2 OP_CHECKMULTISIG witness_script = bytes([ 0x52, # OP_2 0x21, # Push 33 bytes ]) + pubkey1 + bytes([ 0x21, # Push 33 bytes ]) + pubkey2 + bytes([ 0x52, # OP_2 0xAE, # OP_CHECKMULTISIG ]) return witness_script ``` -------------------------------- ### General Numeric Outcome Compression Pattern Source: https://github.com/discreetlogcontracts/dlcspecs/blob/master/NumericOutcomeCompression.md Abstract representation of the compression algorithm grouping logic for a range defined by start and end digits. ```text wxy(z+1), wxy(z+2), ..., wxy(B-1), wx(y+1)_, wx(y+2)_, ..., wx(B-1)_, w(x+1)__, w(x+2)__, ..., w(B-1)__, (w+1)___, (w+2)___, ..., (W-1)___, W0__, W1__, ..., W(X-1)__, WX0_, WX1_, ..., WX(Y-1)_, WXY0, WXY1, ..., WXY(Z-1) ``` -------------------------------- ### DLEQ Verifying Algorithm Source: https://github.com/discreetlogcontracts/dlcspecs/blob/master/ECDSA-adaptor.md Use this algorithm to verify a DLEQ proof. It takes the statement points and the proof as input. Ensure the implied challenge hash matches the one derived from the proof. ```plaintext Parse proof as two scalars (b,c) Set A_G to c * G - b * X Set A_Y to c * Y - b * Z Set implied_b to H(X || Y || Z || A_G || A_Y) Check implied_b == b ``` -------------------------------- ### Implement Multi-Oracle Threshold Schemes Source: https://context7.com/discreetlogcontracts/dlcspecs/llms.txt Uses itertools to generate oracle combinations and aggregates adaptor points for t-of-n threshold execution. ```python from itertools import combinations def get_oracle_combinations(oracles, threshold): """ Generate all t-of-n oracle combinations Returns list of oracle subsets """ return list(combinations(oracles, threshold)) def compute_aggregate_adaptor_point(oracle_points): """ Aggregate adaptor points from multiple oracles S_aggregate = S_1 + S_2 + ... + S_n """ return reduce(point_add, oracle_points) # Example: 2-of-3 oracle setup oracles = [ {"name": "Olivia", "pubkey": olivia_pub, "nonce": olivia_nonce}, {"name": "Oren", "pubkey": oren_pub, "nonce": oren_nonce}, {"name": "Ollivander", "pubkey": ollivander_pub, "nonce": ollivander_nonce} ] # For each outcome, create adaptor signatures for all oracle combinations for combo in get_oracle_combinations(oracles, threshold=2): # Compute aggregate adaptor point for this combination points = [ compute_adaptor_point_single(o["pubkey"], o["nonce"], "outcome_A") for o in combo ] aggregate_point = compute_aggregate_adaptor_point(points) # Create adaptor signature with aggregate point print(f"Combo {[o['name'] for o in combo]}: {aggregate_point.hex()}") ``` -------------------------------- ### Calculate Left Inner and Left Prefixes (Default) Source: https://github.com/discreetlogcontracts/dlcspecs/blob/master/MultiOracle.md Computes leftInnerPrefix and leftPrefix for a large primary interval when maximizeCoverage is false. These prefixes use minSupportExp for width calculation. ```javascript leftInnerPrefix = numToVec(start, numDigits, minSupportExp) leftPrefix = numToVec(start - minSupport, numDigits, minSupportExp) ``` -------------------------------- ### Calculate Right Inner and Right Prefixes (Default) Source: https://github.com/discreetlogcontracts/dlcspecs/blob/master/MultiOracle.md Computes rightInnerPrefix and rightPrefix for a large primary interval when maximizeCoverage is false. These prefixes use minSupportExp for width calculation. ```javascript rightInnerPrefix = numToVec(end - minSupport + 1, numDigits, minSupportExp) rightPrefix = numToVec(end + 1, numDigits, minSupportExp) ``` -------------------------------- ### DLEQ_verify Source: https://github.com/discreetlogcontracts/dlcspecs/blob/master/ECDSA-adaptor.md Algorithm to verify a DLEQ proof. ```APIDOC ## DLEQ_verify ### Description Verifies that the provided proof matches the statement defined by the points (X, Y, Z). ### Parameters - **(X, Y, Z)** (secp256k1 points) - Required - The points defining the statement. - **proof** (scalars) - Required - The proof to verify. ``` -------------------------------- ### Implement DLC oracle signing algorithm Source: https://github.com/discreetlogcontracts/dlcspecs/blob/master/Oracle.md The signing algorithm used for oracle attestations, utilizing BIP 340 and tagged hashes. ```text Let H = tag_hash("DLC/oracle/" || tag) Let m = H(message) Return BIP340_sign(sk, m) ``` -------------------------------- ### ecdsa_adaptor_verify Source: https://github.com/discreetlogcontracts/dlcspecs/blob/master/ECDSA-adaptor.md Algorithm to verify an ECDSA adaptor signature. ```APIDOC ## ecdsa_adaptor_verify ### Description Verifies the validity of an adaptor signature against the signing and encryption keys. ### Parameters - **X** (point) - Required - Signing public key. - **Y** (point) - Required - Encryption public key. - **message_hash** (32-byte array) - Required - Message hash. - **a** (adaptor signature) - Required - The adaptor signature to verify. ``` -------------------------------- ### Define Funding Output Script Source: https://github.com/discreetlogcontracts/dlcspecs/blob/master/Transactions.md The funding output uses a P2WSH script with a 2-of-2 multisig requirement, ordered lexicographically by public key. ```Bitcoin Script 2 2 OP_CHECKMULTISIG ``` -------------------------------- ### Message: offer_dlc_v0 Source: https://github.com/discreetlogcontracts/dlcspecs/blob/master/Protocol.md Details the structure and fields of the offer_dlc_v0 message used to initiate a contract. ```APIDOC ## offer_dlc_v0 (type 42778) ### Description This message contains information about a node and indicates its desire to enter into a new contract. It is the first step toward creating the funding transaction and CETs. ### Request Body - **protocol_version** (u32) - Required - The version of the protocol proposed. - **contract_flags** (byte) - Required - Flags for the contract (currently undefined). - **chain_hash** (chain_hash) - Required - The genesis hash of the blockchain for the contract. - **temporary_contract_id** (32*byte) - Required - Per-peer identifier for the contract. - **contract_info** (contract_info) - Required - Specifies the contract and oracles. - **funding_pubkey** (point) - Required - Public key for the 2-of-2 multisig funding output. - **payout_spk** (spk) - Required - Script pubkey for CETs and refund transaction. - **payout_serial_id** (u64) - Required - Unique identifier for the payout output. - **offer_collateral_satoshis** (u64) - Required - Amount contributed by the sender. - **num_funding_inputs** (bigsize) - Required - Number of funding inputs. - **funding_inputs** (num_funding_inputs*funding_input) - Required - List of funding inputs. - **change_spk** (spk) - Required - Script pubkey for funding change. - **change_serial_id** (u64) - Required - Unique identifier for the change output. - **fund_output_serial_id** (u64) - Required - Unique identifier for the funding output. - **feerate_per_vb** (u64) - Required - Fee rate in satoshi per virtual byte. - **cet_locktime** (u32) - Required - nLockTime for CETs. - **refund_locktime** (u32) - Required - nLockTime for the refund transaction. - **tlvs** (offer_tlvs) - Required - Additional offer TLVs. ``` -------------------------------- ### Funding Transaction Weight Formulas Source: https://github.com/discreetlogcontracts/dlcspecs/blob/master/Transactions.md Formulas for calculating the weight and virtual bytes of funding transactions based on script and witness lengths. ```text // total_change_length = offer_change_spk_script length + accept_change_spk_script length // 212 + (72 + 4*total_change_length) + sum(164 + 4*script_sig_len) weight funding_transaction_weight = 4 * funding_transaction // 2 + sum(offer_max_witness_len) + sum(accept_max_witness_len) weight witness_weight = witness_header + witness * num_inputs overall_funding_tx_weight = 214 + (72 + 4*total_change_length) + sum(164 + 4*script_sig_len + max_witness_len) weight offer_funding_tx_weight = 107 + (36 + 4*offer_change_spk_script length) + sum(164 + 4*offer_script_sig_len + offer_max_witness_len) weight offer_funding_tx_vbytes = Ceil(offer_funding_tx_weight / 4.0) vbytes accept_funding_tx_weight = 107 + (36 + 4*accept_change_spk_script length) + sum(164 + 4*accept_script_sig_len + accept_max_witness_len) weight accept_funding_tx_vbytes = Ceil(accept_funding_tx_weight / 4.0) vbytes ``` -------------------------------- ### DLEQ_prove Source: https://github.com/discreetlogcontracts/dlcspecs/blob/master/ECDSA-adaptor.md Algorithm to generate a non-interactive proof of discrete logarithm equality. ```APIDOC ## DLEQ_prove ### Description Generates a non-interactive proof that the discrete logarithm of X to base G is the same as the discrete logarithm of Z to base Y. ### Parameters - **x** (scalar) - Required - Non-zero witness for the proof. - **(X, Y, Z)** (secp256k1 points) - Required - Three non-zero points defining the statement. ``` -------------------------------- ### Calculate Right Inner and Right Prefixes (Maximize Coverage) Source: https://github.com/discreetlogcontracts/dlcspecs/blob/master/MultiOracle.md Computes rightInnerPrefix and rightPrefix for a large primary interval when maximizeCoverage is true. rightInnerPrefix covers [end - halfMaxError + 1, end] and rightPrefix covers [end + 1, end + 1 + width]. ```javascript rightInnerPrefix = numToVec(end - halfMaxError + 1, numDigits, maxErrorExp - 1) rightPrefix = numToVec(end + 1, numDigits, maxErrorExp - 1) ``` -------------------------------- ### Calculate Right Prefix for Small Primary Interval (Maximize Coverage) Source: https://github.com/discreetlogcontracts/dlcspecs/blob/master/MultiOracle.md Computes the right prefix for a small primary interval when maximizeCoverage is true. This prefix covers the interval [rightMaxErrorMult + 1, rightMaxErrorMult + halfMaxError]. ```javascript rightPrefix = numToVec(rightMaxErrorMult + 1, numDigits, maxErrorExp - 1) ``` -------------------------------- ### offer_dlc Message Source: https://context7.com/discreetlogcontracts/dlcspecs/llms.txt The `offer_dlc` message initiates contract negotiation. It includes contract terms, collateral, funding inputs, and oracle information. ```APIDOC ## offer_dlc Message (Type: 42778) The `offer_dlc` message initiates contract negotiation by specifying contract terms, collateral amounts, funding inputs, and oracle information. ### Request Body ```json { "type": "offer_dlc_v0", "message_type": 42778, "fields": { "protocol_version": 1, "contract_flags": "00", "chain_hash": "06226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f", "temporary_contract_id": "random_32_bytes_hex", "contract_info": { "total_collateral": 100000000, "contract_descriptor": { "type": "enumerated", "outcomes": [ {"outcome": "outcome_A_hash", "payout": 0}, {"outcome": "outcome_B_hash", "payout": 100000000} ] }, "oracle_info": { "oracle_public_key": "x_point_32_bytes", "oracle_nonce": "x_point_32_bytes" } }, "funding_pubkey": "compressed_pubkey_33_bytes", "payout_spk": "0014750b6ce4200e7b23b139d71857c1be1087756b9e", "payout_serial_id": 12345, "offer_collateral_satoshis": 50000000, "funding_inputs": [ { "input_serial_id": 1, "prevtx": "raw_transaction_hex", "prevtx_vout": 0, "sequence": 4294967295, "max_witness_len": 107, "redeemscript": "" } ], "change_spk": "0014e629089b1e317daede966a8e03a64ac0a8a2462f", "change_serial_id": 100, "fund_output_serial_id": 200, "feerate_per_vb": 10, "cet_locktime": 100, "refund_locktime": 200 } } ``` ``` -------------------------------- ### Polynomial Curve Piece Evaluation (Lagrange Interpolation) Source: https://github.com/discreetlogcontracts/dlcspecs/blob/master/PayoutCurve.md Explains how to evaluate a polynomial curve piece using Lagrange Interpolation, given a set of points. ```APIDOC ## Polynomial Curve Piece Evaluation (Lagrange Interpolation) ### Description This section details the process of evaluating a polynomial payout curve for a given `event_outcome` using Lagrange Interpolation. This method computes the unique polynomial defined by the provided interpolation points. ### Algorithm Given a list of points `points` (including endpoints and midpoints), and a potential `event_outcome`: 1. **Define Lagrange Line Function:** `lagrange_line(i, j) = (event_outcome - points(j).event_outcome) / (points(i).event_outcome - points(j).event_outcome)` 2. **Define Lagrange Basis Polynomial:** `lagrange(i) := PRODUCT(j = 0 to points.length - 1, where j != i, lagrange_line(i, j))` 3. **Compute Polynomial Value:** Return `SUM(i = 0 to points.length - 1, points(i).outcome_payout * lagrange(i))` ### Notes - The `points` list should include the start and end points of the curve segment, as well as any specified midpoints. - Alternative interpolation methods like Vandermonde matrix or Divided Differences can also be used, provided they meet validation error tolerances. - Solutions for these algorithms are widely available on programming resource sites. ``` -------------------------------- ### ecdsa_adaptor_encrypt Source: https://github.com/discreetlogcontracts/dlcspecs/blob/master/ECDSA-adaptor.md Algorithm to create an ECDSA adaptor signature. ```APIDOC ## ecdsa_adaptor_encrypt ### Description Encrypts a signature using an adaptor key. ### Parameters - **x** (scalar) - Required - Signing secret key. - **Y** (point) - Required - Encryption public key. - **message_hash** (32-byte array) - Required - Hash of the message. ```