Source code for agora.solana.address
import hashlib
from typing import List, Optional
from pure25519.basic import decodepoint, NotOnCurve
from agora.keys import PublicKey
MAX_SEEDS = 16
MAX_SEED_LENGTH = 32
MAX_UINT8 = 2 ** 8 - 1
[docs]class InvalidPublicKeyError(Exception):
"""
Raised when an invalid public key is generated.
"""
def __init__(self):
super().__init__('invalid public key')
[docs]def create_program_address(program: PublicKey, seeds: List[bytes]) -> PublicKey:
"""Mirrors the implementation of the Solana SDK's CreateProgramAddress. ProgramAddresses are public keys that
_do not_ lie on the ed25519 curve to ensure that there is no associated private key. In the event that the program
and seed parameters result in a valid Public key, InvalidPublicKeyError is raised.
Reference:
https://github.com/solana-labs/solana/blob/5548e599fe4920b71766e0ad1d121755ce9c63d5/sdk/program/src/pubkey.rs#L158
:return :class:`PublicKey <agora.keys.PublicKey>`
"""
if len(seeds) > MAX_SEEDS:
raise ValueError('too many seeds')
sha256 = hashlib.sha256()
for s in seeds:
if len(s) > MAX_SEED_LENGTH:
raise ValueError('max seed length exceeded')
sha256.update(s)
for v in [program.raw, "ProgramDerivedAddress".encode()]:
sha256.update(v)
h = sha256.digest()
pub = h[:32]
# Following the Solana SDK, we want to _reject_ the generated public key if it's a a valid point on the ed25519 curve
try:
decodepoint(pub)
except NotOnCurve:
return PublicKey(pub)
raise InvalidPublicKeyError()
[docs]def find_program_address(program: PublicKey, seeds: List[bytes]) -> Optional[PublicKey]:
"""FindProgramAddress mirrors the implementation of the Solana SDK's FindProgramAddress. Its primary use case (for
Kin and Agora) is for deriving associated accounts.
return: :class:`PublicKey <agora.keys.PublicKey>`
"""
bump_seed = bytes([MAX_UINT8])
for i in range(MAX_UINT8):
try:
pub = create_program_address(program, seeds + [bump_seed])
except InvalidPublicKeyError:
bump_seed = bytes([bump_seed[0] - 1])
continue
return pub
return None