ppad-bolt3-0.0.1: Bitcoin transaction formats per BOLT #3
Copyright(c) 2025 Jared Tobin
LicenseMIT
MaintainerJared Tobin <jared@ppad.tech>
Safe HaskellNone
LanguageHaskell2010

Lightning.Protocol.BOLT3.Keys

Description

Per-commitment key derivation per BOLT #3.

Implements key derivation formulas:

pubkey = basepoint + SHA256(per_commitment_point || basepoint) * G
revocationpubkey = revocation_basepoint * SHA256(revocation_basepoint
                     || per_commitment_point)
                 + per_commitment_point * SHA256(per_commitment_point
                     || revocation_basepoint)
Synopsis

Per-commitment point derivation

derive_per_commitment_point :: PerCommitmentSecret -> Maybe PerCommitmentPoint Source #

Derive the per-commitment point from a per-commitment secret.

per_commitment_point = per_commitment_secret * G
>>> let secret = PerCommitmentSecret (BS.replicate 32 0x01)
>>> derive_per_commitment_point secret
Just (PerCommitmentPoint ...)

Key derivation

derive_pubkey Source #

Arguments

:: Point

basepoint

-> PerCommitmentPoint

per_commitment_point

-> Maybe Pubkey 

Derive a pubkey from a basepoint and per-commitment point.

pubkey = basepoint + SHA256(per_commitment_point || basepoint) * G

This is the general derivation formula used for localpubkey, local_htlcpubkey, remote_htlcpubkey, local_delayedpubkey, and remote_delayedpubkey.

>>> derive_pubkey basepoint per_commitment_point
Just (Pubkey ...)

derive_localpubkey :: PaymentBasepoint -> PerCommitmentPoint -> Maybe LocalPubkey Source #

Derive localpubkey from payment_basepoint and per_commitment_point.

>>> derive_localpubkey payment_basepoint per_commitment_point
Just (LocalPubkey ...)

derive_local_htlcpubkey :: HtlcBasepoint -> PerCommitmentPoint -> Maybe LocalHtlcPubkey Source #

Derive local_htlcpubkey from htlc_basepoint and per_commitment_point.

>>> derive_local_htlcpubkey htlc_basepoint per_commitment_point
Just (LocalHtlcPubkey ...)

derive_remote_htlcpubkey :: HtlcBasepoint -> PerCommitmentPoint -> Maybe RemoteHtlcPubkey Source #

Derive remote_htlcpubkey from htlc_basepoint and per_commitment_point.

>>> derive_remote_htlcpubkey htlc_basepoint per_commitment_point
Just (RemoteHtlcPubkey ...)

derive_local_delayedpubkey :: DelayedPaymentBasepoint -> PerCommitmentPoint -> Maybe LocalDelayedPubkey Source #

Derive local_delayedpubkey from delayed_payment_basepoint and per_commitment_point.

>>> derive_local_delayedpubkey delayed_payment_basepoint per_commitment_point
Just (LocalDelayedPubkey ...)

derive_remote_delayedpubkey :: DelayedPaymentBasepoint -> PerCommitmentPoint -> Maybe RemoteDelayedPubkey Source #

Derive remote_delayedpubkey from delayed_payment_basepoint and per_commitment_point.

>>> derive_remote_delayedpubkey delayed_payment_basepoint pcp
Just (RemoteDelayedPubkey ...)

Revocation key derivation

derive_revocationpubkey :: RevocationBasepoint -> PerCommitmentPoint -> Maybe RevocationPubkey Source #

Derive revocationpubkey from revocation_basepoint and per_commitment_point.

revocationpubkey = revocation_basepoint
                     * SHA256(revocation_basepoint || per_commitment_point)
                 + per_commitment_point
                     * SHA256(per_commitment_point || revocation_basepoint)
>>> derive_revocationpubkey revocation_basepoint per_commitment_point
Just (RevocationPubkey ...)

Per-commitment secret generation

generate_from_seed Source #

Arguments

:: ByteString

seed (32 bytes)

-> Word64

index I (max 2^48 - 1)

-> ByteString

per-commitment secret (32 bytes)

Generate the I'th per-commitment secret from a seed.

Implements the generate_from_seed algorithm from BOLT #3:

generate_from_seed(seed, I):
    P = seed
    for B in 47 down to 0:
        if B set in I:
            flip(B) in P
            P = SHA256(P)
    return P
>>> generate_from_seed seed 281474976710655
<32-byte secret>

derive_secret Source #

Arguments

:: ByteString

base secret

-> Int

bits (number of trailing bits to process)

-> Word64

target index I

-> ByteString

derived secret

Derive a secret from a base secret.

This is a generalization of generate_from_seed used for efficient secret storage. Given a base secret whose index has bits..47 the same as target index I, derive the I'th secret.

derive_secret(base, bits, I):
    P = base
    for B in bits - 1 down to 0:
        if B set in I:
            flip(B) in P
            P = SHA256(P)
    return P

Per-commitment secret storage

data SecretStore Source #

Compact storage for per-commitment secrets.

Stores up to 49 (value, index) pairs, allowing efficient derivation of any previously-received secret. This is possible because for a given secret on a 2^X boundary, all secrets up to the next 2^X boundary can be derived from it.

Instances

Instances details
Generic SecretStore Source # 
Instance details

Defined in Lightning.Protocol.BOLT3.Keys

Associated Types

type Rep SecretStore 
Instance details

Defined in Lightning.Protocol.BOLT3.Keys

Show SecretStore Source # 
Instance details

Defined in Lightning.Protocol.BOLT3.Keys

Eq SecretStore Source # 
Instance details

Defined in Lightning.Protocol.BOLT3.Keys

type Rep SecretStore Source # 
Instance details

Defined in Lightning.Protocol.BOLT3.Keys

empty_store :: SecretStore Source #

Empty secret store.

insert_secret Source #

Arguments

:: ByteString

secret (32 bytes)

-> Word64

index

-> SecretStore

current store

-> Maybe SecretStore 

Insert a secret into the store, validating against existing secrets.

Returns Nothing if the secret doesn't derive correctly from known secrets (indicating the secrets weren't generated from the same seed).

>>> insert_secret secret 281474976710655 empty_store
Just (SecretStore ...)

derive_old_secret Source #

Arguments

:: Word64

target index

-> SecretStore

store

-> Maybe ByteString 

Derive a previously-received secret from the store.

Iterates over known secrets to find one whose index is a prefix of the target index, then derives the target secret from it.

>>> derive_old_secret 281474976710654 store
Just <32-byte secret>

Commitment number obscuring

obscured_commitment_number Source #

Arguments

:: PaymentBasepoint

opener's payment_basepoint

-> PaymentBasepoint

accepter's payment_basepoint

-> CommitmentNumber

commitment number (48-bit)

-> Word64

obscured commitment number

Calculate the obscured commitment number.

The 48-bit commitment number is obscured by XOR with the lower 48 bits of SHA256(payment_basepoint from open_channel || payment_basepoint from accept_channel).

>>> obscured_commitment_number local_payment_bp remote_payment_bp cn
<obscured value>