Crypto Libraries
The following is a guide for implementing a new ARK Cryptography SDK. It covers the required functionalities as well as guidelines for how cryptography should typically look and behave.
These guidelines are to be strictly followed if you are implementing or modifying a cryptography package for the ARK Ecosystem across different programming languages (e.g., PHP, Java, Python, Go, etc.).
Following these guidelines is required to provide a streamlined experience across different languages and to make it easier for new developers to get started with developing a new package or modifying an existing one without lowering the quality of the existing implementation.
Carefully read these guidelines and abide by them while developing a cryptography package.
Required Functionality
Transaction
- sign Sign the transaction using a passphrase or private key instance.
- verify Verify the transaction.
- recoverSender Recovers the sender public key and address based on the transaction's signature.
- serialize Serialize the object according to AIP11.
- deserialize Deserialize the given hex string via AIP11.
- fromJson Map the JSON to a new transaction object.
- toBytes Turn the transaction into its v1 byte representation.
- toArray Turn the transaction into a standardized array.
- toJson Convert the transaction into a JSON string using the
toArray
data as the source.
These functionalities must be present across all implementations, whether in PHP, Java, Python, Go, or any other language.
Message
- sign Create a signed message using the given message and passphrase.
- verify Verify the given message, public key, and signature combination.
- toArray Turn the message into a standardized array.
- toJson Convert the message into a JSON string using the
toArray
data as the source.
Private Key
- fromPassphrase Derive a private key from the given passphrase.
- fromHex Get a private key instance from a private key hex string.
Public Key
- fromPassphrase Derive a public key from the given passphrase.
- fromHex Get a public key instance from a public key hex string.
Address
- fromPassphrase Derive an address from the given passphrase.
- fromPublicKey Derive an address from the given public key.
- fromPrivateKey Derive an address from the given private key.
- validate Validate the given address against the given network.
WIF
- fromPassphrase Derive a WIF from the given passphrase.
Configuration
- getNetwork Get the default network used by all functions.
- setNetwork Set the default network used by all functions.
- getFee Get a default fee by type used by all functions.
- setFee Set a default fee by type used by all functions.
Slot
- time Get the time elapsed since the network start.
- epoch Get the timestamp of the network start.
Networks (Mainnet, Testnet)
- epoch Get the epoch of the network.
- version Get the version of the network.
- nethash Get the nethash of the network.
- wif Get the WIF prefix of the network.
Utils
- parseUnits Convert a given amount to its smallest unit.
- formatUnits Convert a given amount from its smallest unit to the standard unit.
Language-Specific Considerations
While the core functionality is the same, how each functionality is implemented will vary slightly based on the programming language used:
- PHP: Object-oriented, class-based structure with strong use of namespaces.
- Java: A modular class-based system, where cryptographic components (e.g., keys, transactions) are tightly encapsulated within Java classes.
- Go: Go uses a more functional and minimalistic approach. Methods are structured into packages and modules without deep class hierarchies.
- Python: Python implementations rely heavily on dynamic typing and functional approaches, with clear separation of cryptographic identities and utilities.
Things to Keep in Mind
- Use a BigNumber library to handle large values for amounts and fees. Do not use native types like
int
orfloat
for this. - Do not assume what the developer is going to do with the output. If you are working with a buffer, return the buffer instead of a hex-encoded value.
- Add optional helper methods to easily convert identities between
binary
andhex
. For example, allow the private key to be converted to hex viaprivateKey.toHex()
. - Do not add functionality outside of the required functionality. For example, avoid adding niche helper methods unless absolutely necessary.
- Add optional helper methods to derive identities from multiple sources easily. For example,
AddressFromPassphrase
,PublicKeyFromPassphrase
,PublicKeyFromPrivateKey
.
Terminology & Phrasing
- If you use the
ARK
name, remember these two use-cases: the first isARK
in financial contexts like10 ARK
, and the second isARK
for non-financial uses. - When dealing with functions requiring a secret or passphrase, name the variables
passphrase
andsecondPassphrase
. - Always use American English spelling for terms like
serialization
anddeserialization
.
File & Directory Structure
The structure outlined here should be followed as closely as possible. Adjustments may be necessary for different programming languages, particularly in functional programming languages like Go or Python. Below is a generic structure that can apply across languages.
[src | lib | crypto]
├── Configuration
│ ├── Fee
│ └── Network
├── Enums
│ ├── Fees
│ └── Types
├── Identities
│ ├── Address
│ ├── PrivateKey
│ ├── PublicKey
│ └── WIF
├── Networks
│ ├── Mainnet
│ └── Testnet
├── Transactions
│ ├── Builder
│ │ ├── EvmCall
│ │ ├── Multipayment
│ │ ├── Transfer
│ │ ├── Unvote
│ │ ├── UsernameRegistration
│ │ ├── UsernameResignation
│ │ ├── ValidatorRegistration
│ │ ├── ValidatorResignation
│ │ └── Unvote
│ ├── Deserializer
│ ├── Serializer
│ └── Transaction
└── Utils
├── Message
└── Slot
This structure works well in Object-Oriented languages such as PHP and Java. In Go and Python, however, it might be flatter, using packages and smaller modules instead of nested classes.
Testing
Testing is vital across all languages. Use unit tests to ensure each cryptographic operation (e.g., signing, verification, deserialization) behaves as expected. Common testing strategies include:
- PHP: Use PHPUnit and mock cryptographic objects to simulate various scenarios.
- Java: Utilize JUnit for extensive test coverage, including edge cases in cryptographic processes.
- Go: Test coverage can be performed using
go test
, with specific attention to concurrency and race conditions (use-race
). - Python: Use pytest for testing cryptographic operations and edge cases.
Examples from Existing Implementations
You can refer to the following repositories for examples of cryptographic package structures in different languages:
- PHP: https://github.com/ArkEcosystem/php-crypto
- Java: https://github.com/ArkEcosystem/java-crypto
- Go: https://github.com/ArkEcosystem/go-crypto
- Python: https://github.com/ArkEcosystem/python-crypto
Implementation
The tools available for implementing cryptography vary based on the programming language. Below are some approaches for different types of languages:
Object-Oriented Programming (OOP)
In OOP languages like PHP or Java, use classes to represent cryptographic concepts such as transactions, keys, and addresses. This allows you to encapsulate functionality within clear boundaries.
Functional and Dynamic Programming
In languages like Go and Python, you'll typically use functions and modules to handle cryptographic operations. Instead of classes, these languages use packages to organize related functionality.
Make sure to follow the core guidelines of each language, while maintaining consistency in the features and structure outlined here.