Search documentation of Cartouche

# Cartouche.Solana.PDA (Cartouche v0.1.3)

Copy Markdown View Source

Program Derived Addresses (PDAs) for Solana.

A PDA is an address derived from seeds and a program ID that is guaranteed to NOT be on the Ed25519 curve (no private key can sign for it). Only the owning program can "sign" for a PDA via cross-program invocation.

## Examples

    iex> {:ok, {address, bump}} = Cartouche.Solana.PDA.find_program_address(["hello"], <<0::256>>)
    iex> byte_size(address)
    32
    iex> bump >= 0 and bump <= 255
    true

## Summary

### Functions

create_program_address(seeds, arg)

Create a program address from seeds (including bump) and program ID.

find_program_address(seeds, arg)

Find a program-derived address from seeds and a program ID.

find_program_address!(seeds, program_id)

Like `find_program_address/2`, but raises on failure.

on_curve?(arg)

Check if 32 bytes represent a valid Ed25519 public key (on the curve).

## Functions

# create_program_address(seeds, arg)

    @spec create_program_address([binary()], <<_::256>>) ::
      {:ok, <<_::256>>} | {:error, :on_curve}

Create a program address from seeds (including bump) and program ID.

Returns `{:ok, address}` if the result is off-curve, or `{:error, :on_curve}` if the candidate is on the Ed25519 curve.

This is the single-attempt version where the caller provides the bump seed as part of the seeds list.

## Examples

    iex> {address, bump} = Cartouche.Solana.PDA.find_program_address!(["test"], <<0::256>>)
    iex> {:ok, ^address} = Cartouche.Solana.PDA.create_program_address(["test", <<bump>>], <<0::256>>)
    iex> byte_size(address)
    32

# find_program_address(seeds, arg)

    @spec find_program_address([binary()], <<_::256>>) ::
      {:ok, {<<_::256>>, non_neg_integer()}} | {:error, :no_valid_pda}

Find a program-derived address from seeds and a program ID.

Tries bump seeds from 255 down to 0, returning the first off-curve result.

## Examples

    iex> {:ok, {_address, bump}} = Cartouche.Solana.PDA.find_program_address(["hello"], <<0::256>>)
    iex> bump >= 0 and bump <= 255
    true

# find_program_address!(seeds, program_id)

    @spec find_program_address!([binary()], <<_::256>>) :: {<<_::256>>, non_neg_integer()}

Like `find_program_address/2`, but raises on failure.

## Examples

    iex> {_address, bump} = Cartouche.Solana.PDA.find_program_address!(["hello"], <<0::256>>)
    iex> bump >= 0 and bump <= 255
    true

# on_curve?(arg)

    @spec on_curve?(<<_::256>>) :: boolean()

Check if 32 bytes represent a valid Ed25519 public key (on the curve).

Uses Ed25519 compressed point decompression: interprets the bytes as a y-coordinate and checks if the corresponding x² is a quadratic residue mod p. Uses `:crypto.mod_pow/3` for efficient modular exponentiation.

## Examples

    iex> valid_pub = Base.decode16!("D75A980182B10AB7D54BFED3C964073A0EE172F3DAA62325AF021A68F707511A")
    iex> Cartouche.Solana.PDA.on_curve?(valid_pub)
    true

    iex> Cartouche.Solana.PDA.on_curve?(<<0::256>>)
    true