Cryptography in Move
Cryptography plays an integral role in ensuring the security, integrity, confidentiality, and immutability of data in blockchain systems. The Aptos adapter for Move provides developers with an array of cryptographic primitives to cater to this need. This document delves into the cryptographic functionalities offered by Move on Aptos and elucidates the principles that drive their design.
Cryptographic primitives
Move, through the Aptos adapter, encompasses several fundamental cryptographic tools:
 Cryptographic Hash Functions – Algorithms that produce a fixedsize output (hash) from variablesized input data. Supported functions include SHA2256, SHA3256, Keccak256, and Blake2b256.
 Digital Signature Verification – Algorithms for signing a message to ensure its integrity, authenticate its sender, ensure nonrepudiation, or any combination thereof. Supported signature schemes include Ed25519, ECDSA, and BLS.
 Elliptic Curve Arithmetic – Elliptic curves are one of the building blocks of advanced cryptographic primitives, such as digital signatures, publickey encryption or verifiable secret sharing. Supported curves include Ristretto255 and BLS12381.
 ZeroKnowledge Proofs (ZKP) – These cryptographic techniques enable a party to prove that a relation $R(x; w)$ is satisfied on a public statement $x$ without leaking the secret witness $w$ that makes it hold. Currently, we support Groth16 ZKP verification and Bulletproofs ZK range proof verification.
Three fundamental principles guide the design and integration of the Aptos cryptographic extensions into Move:
 Economic Gas Usage – Striving to minimize gas costs for Move developers by implementing key primitives as Move native functions. For example, see the module for BLS signatures over BLS12381 elliptic curves.
 TypeSafe APIs – Ensuring that APIs are resistant to common mistakes, typesafety enhances code reliability and promotes an efficient development process. For an example, see the Ed25519 signature module.
 Empowerment of Developers – In instances where native functions are unavailable, we empower developers to build their own cryptographic primitives on top of abstract cryptographic building blocks such as finite fields and Abelian groups. Refer to the
aptos_std::crypto_algebra
module for more insights.
Continue reading to delve a bit deeper and uncover some of the intricacies behind these extensions, as well as the range of applications they empower. For the most comprehensive understanding of this subject, refer to the cryptography Move modules code.
Cryptographic hash functions
Developers can now use more cryptographic hash functions in Move via the aptos_std::aptos_hash
module:
Hash function  Hash size (bits)  Cost for hashing 1KiB (in internal gas units)  Collisionresistance security (bits) 

Keccak256  256  1,001,600  128 
SHA2256  256  1,084,000  128 
SHA2512  512  1,293,600  256 
SHA3256  256  1,001,600  128 
SHA3512  512  1,114,000  256 
RIPEMD160  160  1,084,000  80 (weak) 
Blake2b256  256  342,200  128 
All hash functions have the same security properties (e.g., onewayness, collision resistance, etc.), but their security levels are different.
RIPEMD160 should be avoided as a collisionresistant function due to its 80bit security level. It is mainly supported for backwardcompatibility reasons: e.g., Bitcoin address derivation relies on RIPEMD160.
Some of these functions can be used for interoperability with other chains (e.g., verifying Ethereum Merkle proofs via aptos_std::aptos_hash::keccak256
).
Others, have lower gas costs, such as aptos_std::aptos_hash::blake2b_256
.
In general, a wider variety of hash functions give developers additional freedom in terms of both security and interoperability with other offchain cryptographic systems.
Digital signature verification
Developers can now use a typesafe API for verifying many kinds of digital signatures in Move:
Signature scheme  Curve  Sig. size (bytes)  PK size (bytes)  Malleability  Assumptions  Pros  Cons 

ECDSA  secp256k1  64  64  Yes  GGM  Wide adoption  Security proof 
Ed25519  Edwards 25519  64  32  No  DLA, ROM  Fast  Subtleties 
MultiEd25519  Edwards 25519  $4 + t \cdot 64$  $n \cdot 32$  No  DLA, ROM  Easytoadopt  Large sig. size 
MinPK BLS  BLS12381  96  48  No  CDH, ROM  Versatile  Slower verification 
MinSig BLS  BLS12381  48  96  No  CDH, ROM  Versatile  Slower verification 
 CDH stands for the “Computational DiffieHellman Assumption”
 DLA stands for the “Discrete Log Assumption”
 GGM stands for the “Generic Group Model”
 ROM stands for the “Random Oracle Model”
The digital signature modules above can be used to build smart contractbased wallets, secure claiming mechanisms for airdrops, or any digitalsignaturebased accesscontrol mechanism for dapps.
The right choice of a signature scheme in your dapp could depend on many factors:
 Backwardscompatibility
 If your dapp’s user base predominantly uses a particular signing mechanism, it would be prudent to support that mechanism for ease of transition and adoption.
 Example: If users mainly sign using Ed25519, it becomes a logical choice.
 If your dapp’s user base predominantly uses a particular signing mechanism, it would be prudent to support that mechanism for ease of transition and adoption.
 Easeofimplementation
 While theoretically sound, complex protocols may be challenging to implement in practice.
 Example: Even though $t$outof$n$ threshold protocols for Ed25519 exist, their intricacy on the signer’s side might push developers toward MultiEd25519 due to its more straightforward signing implementation.
 While theoretically sound, complex protocols may be challenging to implement in practice.
 Efficiency
 Depending on the dapp’s requirements, you might prioritize one aspect of efficiency over another.
 Signature size vs. public key size: Some applications might prioritize a smaller signature footprint, while others might emphasize a compact PK.
 Signing time vs. verification time: For certain dapps, the signing speed might be more crucial, while for others, rapid signature verification could be the priority.
 Depending on the dapp’s requirements, you might prioritize one aspect of efficiency over another.
 Security analysis
 It is essential to consider the underlying assumptions and potential vulnerabilities of a signature scheme.
 Example: ECDSA’s security is proven under strong assumptions such as the Generic Group Model (GGM).
 Malleability concerns: Some signature schemes are susceptible to malleability, where a valid signature, $\sigma$, can be mauled into a different yet still valid signature, $\sigma$, for the same message $m$.
 It is essential to consider the underlying assumptions and potential vulnerabilities of a signature scheme.
 Versatility
 The adaptability and flexibility of signature schemes are important to consider, so you may properly accommodate the cryptographic needs of your dapp.
 Example: $t$outof$n$ threshold BLS signatures are very simple to implement.
 The adaptability and flexibility of signature schemes are important to consider, so you may properly accommodate the cryptographic needs of your dapp.
Despite its careful, principled design^{1}, Ed25519 has known implementation subtleties. For example, different implementations could easily disagree on the validity of signatures, especially when batch verification is employed^{2}$^,$^{3}.
Our aptos_std::bls12381
module for MinPK BLS supports verification of individual signatures, multisignatures, aggregate signatures and threshold signatures.
Elliptic curve arithmetic
While the hash function and digital signature modules should provide enough functionality for most applications, some applications will require more powerful cryptography. Normally, developers of such applications would have to wait until their desired cryptographic functionality is implemented efficiently as a Move native function in the Aptos Move framework. Instead, we expose basic building blocks that developers can use to implement their own cryptographic primitives directly in the Move language and do so efficiently.
Specifically, we currently expose lowlevel arithmetic operations on two popular elliptic curve groups and their associated finite fields:
 Ristretto255, via
aptos_std::ristretto255
 BLS12381, via
aptos_std::crypto_algebra
andaptos_std::bls12381_algebra
These modules support lowlevel operations such as:
 scalar multiplication of elliptic curve points
 multiscalar multiplications (MSMs)
 pairings
 scalar addition, multiplication, inversion
 hashing to a scalar or to a point
 and many more
Examples of powerful applications that can be built on top include:
 Validity rollups – See the
groth16
zkSNARK verifier example.  Randomnessbased games – See the
drand
verifier example.  Privacypreserving applications – See the
veiled_coin
example.
Ristretto255 arithmetic
The aptos_std::ristretto255
module provides support for elliptic curve arithmetic on the popular Ristretto255 curve.
One of the main advantages of Ristretto255 is that it is a prime order group (unlike the Edwards 25519 curve), which obviates smallsubgroup attacks on higherlevel cryptosystems built on top of it.
Furthermore, Ristretto255 serialization is canonical and deserialization only accepts canonical encodings, which obviates malleability issues in higherlevel protocols.
This module has proven useful for implementing several cryptographic primitives:
 Zeroknowledge $\Sigma$protocols – See the
veiled_coin
example.  ElGamal encryption – See
aptos_std::ristretto255_elgamal
 Pedersen commitments – See
aptos_std::ristretto255_pedersen
 Bulletproofs ZK range proofs^{4} – See
aptos_std::ristretto255_bulletproofs
Need ideas for a cryptosystem to build on top of ristretto255
?
A popular primitive that you could easily build would be the schnorrkel signature scheme, which is a hardened version of Schnorr signatures over Ristretto255 groups.
Generic elliptic curve arithmetic
What is better than one curve? More curves!
The aptos_std::crypto_algebra
provides elliptic curve arithmetic operations for any supported elliptic curve, including pairingfriendly curves.
As a consequence, Move developers can implement a cryptosystem generically over any curve that is or will be supported in the future.
Compared to fixing a particular curve in the code (e.g., by implementing against the Ristretto255 module), this approach provides more flexibility and lowers development time when migrating to a different curve.
Although currently the crypto_algebra
module only supports arithmetic over BLS12381 curves (via the marker types declared in aptos_std::bls12381_algebra
), more curves will be supported into the future (e.g., BN254, Ristretto255, BLS12377, BW6761, secp256k1, secp256r1).
As an example, a Move developer can implement the popular BonehLynnShacham (BLS) signature scheme generically over any curve by using type arguments for the curve type in their implementation:
use std::option;
use aptos_std::crypto_algebra::{eq, pairing, one, deserialize, hash_to};
/// Example of a BLS signature verification function that works over any pairingfriendly
/// group triple `Gr1`, `Gr2`, `GrT` where signatures are in `Gr1` and PKs in `Gr2`.
/// Points are serialized using the format in `FormatG1` and `FormatG2` and the hashing
/// method is `HashMethod`.
///
/// WARNING: This example is typeunsafe and probably not a great fit for production code.
public fun bls_verify_sig<Gr1, Gr2, GrT, FormatG1, FormatG2, HashMethod>(
dst: vector<u8>,
signature: vector<u8>,
message: vector<u8>,
public_key: vector<u8>): bool
{
let sig = option::extract(&mut deserialize<Gr1, FormatG1>(&signature));
let pk = option::extract(&mut deserialize<Gr2, FormatG2>(&public_key));
let hash = hash_to<Gr1, HashMethod>(&dst, &message);
// Checks if $e(H(m), pk) = e(sig, g_2)$, where $g_2$ generates $\mathbb{G}_2$
eq(
&pairing<Gr1, Gr2, GrT>(&hash, &pk),
&pairing<Gr1, Gr2, GrT>(&sig, &one<Gr2>())
)
}
Using the bls_verify_sig
generic function from above, developers can verify BLS signatures over any of the supported (pairingfriendly) curves.
For example, one can verify MinSig BLS signatures over BLS12381 curves by calling the function above with the right BLS12381 marker types as its type arguments:
use aptos_std::bls12381_algebra::{
G1, G2, Gt, FormatG1Compr, FormatG2Compr, HashG1XmdSha256SswuRo
};
// Aborts with code 1 if the MinSig BLS signature over the BLS12381 curve fails to verify.
assert(
bls_verify_sig<G1, G2, Gt, FormatG1Compr, FormatG2Compr, HashG1XmdSha256SswuRo>(
dst, signature, message, public_key
),
1
);
For more use cases of the crypto_algebra
module, check out some Move examples:
Building powerful cryptographic applications
Veiled coins
The veiled_coin
example demonstrates how to use the Ristretto255 modules from above to add a reasonable layer of confidentiality to coin balances and transactions.
Specifically, users can veil their balance, keeping it hidden from everyone, including validators. Furthermore, a user can send a veiled transaction that hides the transaction amount from everybody, including validators. An important caveat is that veiled transactions do not hide the identities of the sender or the recipient.
This module is educational. It is not productionready. Using it could lead to loss of funds.
Groth16 zkSNARK verifier
The groth16
example demonstrates how to verify Groth16 zkSNARK proofs^{5}, which are the shortest, fastesttoverify, generalpurpose zeroknowledge proofs.
Importantly, as explained above, this implementation is generic over any curve, making it very easy for Move developers to use it with their favorite (supported) curves.
This code has not been audited by a thirdparty organization. If using it in a production system, proceed at your own risk.
Verifying randomness from the drand
beacon
The drand
example shows how to verify public randomness from the drand randomness beacon.
This randomness can be used in games or any other chancebased smart contract.
We give a simple example of a lottery implemented on top of drand
randomness in lottery.move
.
This code has not been audited by a thirdparty organization. If using it in a production system, proceed at your own risk.
Another application that can be built on top of drand
is timelock encryption^{6}, which allows users to encrypt information such that it can only be decrypted in a future block.
We do not currently have an implementation but the reader is encouraged to write one!
Footnotes

ed25519: Ed25519: highspeed highsecurity signatures, by Daniel J. Bernstein, Niels Duif, Tanja Lange, Peter Schwabe, BoYin Yang, https://ed25519.cr.yp.to/ ↩

devalence: It’s 255:19AM. Do you know what your validation criteria are?, by Henry de Valence, https://hdevalence.ca/blog/20201004its25519am ↩

eddsa: Taming the Many EdDSAs, by Konstantinos Chalkias, François Garillot, Valeria Nikolaenko, in SSR 2020, https://dl.acm.org/doi/abs/10.1007/9783030643577_4 ↩

bulletproofs: Bulletproofs: Short Proofs for Confidential Transactions and More; by B. Bünz and J. Bootle and D. Boneh and A. Poelstra and P. Wuille and G. Maxwell; in 2018 IEEE Symposium on Security and Privacy ↩

groth16: On the Size of PairingBased Noninteractive Arguments; by Groth, Jens; in EUROCRYPT 2016 ↩

tlock: tlock: Practical Timelock Encryption from Threshold BLS; by Nicolas Gailly and Kelsey Melissaris and Yolan Romailler; https://eprint.iacr.org/2023/189 ↩