# Crypto

## Hashing

The built-in enum `HashAlgorithm`

provides the set of hashing algorithms that
are supported by the language natively.

```
pub enum HashAlgorithm: UInt8 {
/// SHA2_256 is Secure Hashing Algorithm 2 (SHA-2) with a 256-bit digest.
pub case SHA2_256 = 1
/// SHA2_384 is Secure Hashing Algorithm 2 (SHA-2) with a 384-bit digest.
pub case SHA2_384 = 2
/// SHA3_256 is Secure Hashing Algorithm 3 (SHA-3) with a 256-bit digest.
pub case SHA3_256 = 3
/// SHA3_384 is Secure Hashing Algorithm 3 (SHA-3) with a 384-bit digest.
pub case SHA3_384 = 4
/// KMAC128_BLS_BLS12_381 is an instance of KECCAK Message Authentication Code (KMAC128) mac algorithm,
/// that can be used as the hashing algorithm for BLS signature scheme on the curve BLS12-381.
/// This is a customized version of KMAC128 that is compatible with the hashing to curve
/// used in BLS signatures.
pub case KMAC128_BLS_BLS12_381 = 5
/// KECCAK_256 is the legacy Keccak algorithm with a 256-bits digest, as per the original submission to the NIST SHA3 competition.
/// KECCAK_256 is different than SHA3 and is used by Ethereum.
pub case KECCAK_256 = 6
/// Returns the hash of the given data
pub fun hash(_ data: [UInt8]): [UInt8]
/// Returns the hash of the given data and tag
pub fun hashWithTag(_ data: [UInt8], tag: string): [UInt8]
}
```

`hash`

hashes the input data using the input hashing algorithm. If`KMAC128_BLS_BLS12_381`

is used, data is hashed using the standard MAC`KMAC128(customizer, key, data, length)`

with the following inputs:`customizer`

is the UTF-8 encoding of`"H2C"`

`key`

is the UTF-8 encoding of`"APP_BLS_SIG_BLS12381G1_XOF:KMAC128_SSWU_RO_POP_"`

`data`

is the input data to hash`length`

is 1024 bytes

`hashWithTag`

hashes data along with a tag. This allows instanciating independent hashing functions customized with a domain separation tag. This is implemented differently depending on the hashing algorithm:`SHA2_256`

,`SHA2_384`

,`SHA3_256`

,`SHA3_384`

: The hashed message is`bytes(tag) || data`

where`bytes()`

is the UTF-8 encoding of the input string, padded with zeros till 32 bytes. The tags accepted must not exceed 32 bytes. If the tag used is empty, no data prefix is applied, and the hashed message is simply`data`

.`KMAC128_BLS_BLS12_381`

: this is a call to standard`KMAC128(customizer, key, data, length)`

with the following inputs:`customizer`

is the UTF-8 encoding of`"H2C"`

`key`

is the UTF-8 encoding of`"APP_" || tag || "BLS_SIG_BLS12381G1_XOF:KMAC128_SSWU_RO_POP_"`

`data`

is the input data to hash`length`

is 1024 bytes

For example, to compute a SHA3-256 hash:

```
let data: [UInt8] = [1, 2, 3]
let digest = HashAlgorithm.SHA3_256.hash(data)
```

## Signing Algorithms

The built-in enum `SignatureAlgorithm`

provides the set of signing algorithms that
are supported by the language natively.

```
pub enum SignatureAlgorithm: UInt8 {
/// ECDSA_P256 is Elliptic Curve Digital Signature Algorithm (ECDSA) on the NIST P-256 curve.
pub case ECDSA_P256 = 1
/// ECDSA_secp256k1 is Elliptic Curve Digital Signature Algorithm (ECDSA) on the secp256k1 curve.
pub case ECDSA_secp256k1 = 2
/// BLS_BLS12_381 is BLS signature scheme on the BLS12-381 curve.
/// The scheme is set-up so that signatures are in G_1 (curve over the prime field)
/// while public keys are in G_2 (curve over the prime field extension).
pub case BLS_BLS12_381 = 3
}
```

## PublicKey

`PublicKey`

is a built-in structure that represents a cryptographic public key of a signature scheme.

```
struct PublicKey {
let publicKey: [UInt8]
let signatureAlgorithm: SignatureAlgorithm
let isValid: Bool
/// Verifies a signature under the given tag, data and public key.
/// It uses the given hash algorithm to hash the tag and data.
pub fun verify(
signature: [UInt8],
signedData: [UInt8],
domainSeparationTag: String,
hashAlgorithm: HashAlgorithm
): Bool
/// Verifies the proof of possession of the private key.
/// This function is only implemented if the signature algorithm of the public key is BLS, it errors if called with any other signature algorithm.
pub fun verifyPoP(_ proof: [UInt8]): Bool
}
```

A `PublicKey`

can be constructed using the raw key and the signing algorithm.

```
let publicKey = PublicKey(
publicKey: "010203".decodeHex(),
signatureAlgorithm: SignatureAlgorithm.ECDSA_P256
)
```

The raw key value depends on the supported signature scheme:

`ECDSA_P256`

and`ECDSA_secp256k1`

: The public key is a curve point`(X,Y)`

where`X`

and`Y`

are two prime field elements. The raw key is represented as`bytes(X) || bytes(Y)`

, where`||`

is the concatenation operation, and`bytes()`

is the bytes big-endian encoding of the input integer padded by zeros to the byte-length of the field prime. The raw public key is 64-bytes long.`BLS_BLS_12_381`

: The public key is a G_2 (curve over the prime field extension) element. The encoding follows the compressed serialization defined in the IETF draft-irtf-cfrg-pairing-friendly-curves-08. A public key is 96-bytes long.

A public key is validated at the time of creation. Hence, public keys are immutable.

```
publicKey.signatureAlgorithm = SignatureAlgorithm.ECDSA_secp256k1 // Not allowed
publicKey.publicKey = [] // Not allowed
publicKey.publicKey[2] = 4 // No effect
```

The validity of a public key can be checked using the `isValid`

field.
Verifications performed with an invalid public key (using `verify()`

method) will always fail.

### Signature verification

A signature can be verified using the `verify`

function of the `PublicKey`

:

```
let pk = PublicKey(
publicKey: "96142CE0C5ECD869DC88C8960E286AF1CE1B29F329BA4964213934731E65A1DE480FD43EF123B9633F0A90434C6ACE0A98BB9A999231DB3F477F9D3623A6A4ED".decodeHex(),
signatureAlgorithm: SignatureAlgorithm.ECDSA_P256
)
let signature = "108EF718F153CFDC516D8040ABF2C8CC7AECF37C6F6EF357C31DFE1F7AC79C9D0145D1A2F08A48F1A2489A84C725D6A7AB3E842D9DC5F8FE8E659FFF5982310D".decodeHex()
let message : [UInt8] = [1, 2, 3]
let isValid = pk.verify(
signature: signature,
signedData: message,
domainSeparationTag: "",
hashAlgorithm: HashAlgorithm.SHA2_256
)
// `isValid` is false
```

The inputs to `verify()`

depend on the signature scheme used:

ECDSA (

`ECDSA_P256`

and`ECDSA_secp256k1`

):`signature`

is the couple`(r,s)`

. It is represented as`bytes(r) || bytes(s)`

, where`||`

is the concatenation operation, and`bytes()`

is the bytes big-endian encoding of the input integer padded by zeros to the byte-length of the curve order. The signature is 64 bytes-long for both curves.`signedData`

is the arbitrary message to verify the signature against.`domainSeparationTag`

is the domain tag used for signing. The interface only accepts the the user tag`"FLOW-V0.0-user"`

.`hashAlgorithm`

is the algorithm used to hash the message along with the given tag (check the`hashWithTag`

function for more details). Only`SHA2_256`

or`SHA3_256`

are accepted.

BLS (

`BLS_BLS_12_381`

):`signature`

is a G_1 (curve over the prime field) point. The encoding follows the compressed serialization defined in the IETF draft-irtf-cfrg-pairing-friendly-curves-08. A signature is 48-bytes long.`signedData`

is the arbitrary message to verify the signature against.`domainSeparationTag`

is the domain tag used for signing. All tags are accepted.`hashAlgorithm`

is the algorithm used to hash the message along with the given tag (check`hashWithTag`

function for more details). Only`KMAC128_BLS_BLS12_381`

is accepted.

BLS verification performs the necessary membership check of the signature while the membership check of the public key is performed at the creation of the `PublicKey`

object.

The BLS signature scheme also supports two additional operations on keys and signatures:

```
/// This is a specific function for the BLS signature scheme. It aggregate multiple BLS signatures into one,
/// considering the proof of possession as a defence against the rogue attacks.
///
/// Signatures could be generated from the same or distinct messages, they
/// could also be the aggregation of other signatures.
/// The order of the signatures in the slice does not matter since the aggregation is commutative.
/// No subgroup membership check is performed on the input signatures.
/// The function errors if the array is empty or if decoding one of the signature fails.
AggregateBLSSignatures(_ signatures: [[UInt8]]): [UInt8]
/// This is a specific function for the BLS signature scheme. It aggregates multiple BLS public keys into one.
///
/// The order of the public keys in the slice does not matter since the aggregation is commutative.
/// No subgroup membership check is performed on the input keys.
/// The function errors if the array is empty or any of the input keys is not a BLS key.
AggregateBLSPublicKeys(_ signatures: [PublicKey]): PublicKey
```

## Crypto Contract

The built-in contract `Crypto`

can be used to perform cryptographic operations.
The contract can be imported using `import Crypto`

.

### Key Lists

The crypto contract also allows creating key lists to be used for multi-signature verification. For example, to verify two signatures with equal weights for some signed data:

```
import Crypto
pub fun test main() {
let keyList = Crypto.KeyList()
let publicKeyA = PublicKey(
publicKey:
"db04940e18ec414664ccfd31d5d2d4ece3985acb8cb17a2025b2f1673427267968e52e2bbf3599059649d4b2cce98fdb8a3048e68abf5abe3e710129e90696ca".decodeHex(),
signatureAlgorithm: SignatureAlgorithm.ECDSA_P256
)
keyList.add(
publicKeyA,
hashAlgorithm: HashAlgorithm.SHA3_256,
weight: 0.5
)
let publicKeyB = PublicKey(
publicKey:
"df9609ee588dd4a6f7789df8d56f03f545d4516f0c99b200d73b9a3afafc14de5d21a4fc7a2a2015719dc95c9e756cfa44f2a445151aaf42479e7120d83df956".decodeHex(),
signatureAlgorithm: SignatureAlgorithm.ECDSA_P256
)
keyList.add(
publicKeyB,
hashAlgorithm: HashAlgorithm.SHA3_256,
weight: 0.5
)
let signatureSet = [
Crypto.KeyListSignature(
keyIndex: 0,
signature:
"8870a8cbe6f44932ba59e0d15a706214cc4ad2538deb12c0cf718d86f32c47765462a92ce2da15d4a29eb4e2b6fa05d08c7db5d5b2a2cd8c2cb98ded73da31f6".decodeHex()
),
Crypto.KeyListSignature(
keyIndex: 1,
signature:
"bbdc5591c3f937a730d4f6c0a6fde61a0a6ceaa531ccb367c3559335ab9734f4f2b9da8adbe371f1f7da913b5a3fdd96a871e04f078928ca89a83d841c72fadf".decodeHex()
)
]
// "foo", encoded as UTF-8, in hex representation
let signedData = "666f6f".decodeHex()
let isValid = keyList.verify(
signatureSet: signatureSet,
signedData: signedData
)
}
```

The API of the Crypto contract related to key lists is:

```
pub struct KeyListEntry {
pub let keyIndex: Int
pub let publicKey: PublicKey
pub let hashAlgorithm: HashAlgorithm
pub let weight: UFix64
pub let isRevoked: Bool
init(
keyIndex: Int,
publicKey: PublicKey,
hashAlgorithm: HashAlgorithm,
weight: UFix64,
isRevoked: Bool
)
}
pub struct KeyList {
init()
/// Adds a new key with the given weight
pub fun add(
_ publicKey: PublicKey,
hashAlgorithm: HashAlgorithm,
weight: UFix64
)
/// Returns the key at the given index, if it exists.
/// Revoked keys are always returned, but they have `isRevoked` field set to true
pub fun get(keyIndex: Int): KeyListEntry?
/// Marks the key at the given index revoked, but does not delete it
pub fun revoke(keyIndex: Int)
/// Returns true if the given signatures are valid for the given signed data
pub fun verify(
signatureSet: [KeyListSignature],
signedData: [UInt8]
): Bool
}
pub struct KeyListSignature {
pub let keyIndex: Int
pub let signature: [UInt8]
pub init(keyIndex: Int, signature: [UInt8])
}
```