Cryptography Primitives
1. Pairing Groups on BN-254
Aztec uses the Ethereum-native version of the BN254 elliptic curve for its principal group:
First pairing source group
A BN curve of size , with field size , and security of roughly 110 bits (practically, this can be closer to 128 bits as the stronger attacks require unproven assumptions related to number field sive algorithms and have never been fully specified or implemented).
- Equation
- Parameters
- Field for prime in decimal representation (size)
- Group of prime order (size)
- Generator
We have . As usual, we use a subgroup of a twist of the above curve for efficient pairings:
Second pairing source group
A subgroup of size , of a curve over field size . This is a degree-2 field extension of , via . Note that is the ideal generated by , whose roots are .
- Equation
- Parameters
- Field for as above.
- Group = subgroup of of the same prime order as .
- Generator
Pairing
We use the Ethereum-native Ate pairing, a bilinear map taking:
Where is a field extension of of degree 12.
Further details may be found here.
2. Grumpkin - A curve on top of BN-254 for SNARK efficient group operations.
Grumpkin is in fact a curve cycle together with BN-254, meaning that the field and group order of Grumpkin are equal to the group and field order of (the first pairing group of) BN-254:
- Equation
- Parameters
- Group of order
- Base field for
3. Hashes
The Aztec 2.0 system relies on two types of hashes:
- Pedersen Hashes (for collision resistance)
- Blake2 Hashes (for pseudorandomness)
Aztec relies overwhelmingly on Pedersen Hashes; as most of the time collision resistance is sufficient.
Pedersen Hashes
Let be an additive group of prime order .
In its classical setting a pedersen hash is defined as a map as follows:
for generators chosen independently by public randomness (e.g. hueristically as distinct outputs of a random oracle simulating hash function).
We wish to define a variant of Pedersen to enable hashing strings of any desired length. As our group we will use the Grumpkin curve group described above.
We generate a sequence of generators as hash outputs -- these are network parameters, fixed for the life of the protocol. They are simply chosen to be the first Keccak-256 outputs that correspond to group elements. See the derive_generators
method in the barretenberg code and the Global Constants section below for exact details.
Hashing field elements
Our basic component for hashing will be the hash_single
method.
Given a field element and hash index , we essentially hash 252 bits of with and the the remaining 2 bits of with . This is not precisely the case, as we use a wnaf representation - see page 4 here. See the comments above hash_single
in the code for exact details. The point is that while enforcing the wnaf representation to represent an integer smaller than , this is a collision resistant function from under DL, even when outputting only the -coordinate.
Now, given a vector we define the pedersen hash as
Hashing byte arrays:
Given a message of arbitrary size, we first divide it up into -byte chunks ; in other words:
We now identify each with a field element in the natural way. and now we define
For details on how have been generated, please see Global Constants.
Blake2s Hash
We use the Blake2s Hash more sparingly, because it is not SNARK-friendly, but it does exhibit psuedorandomness not offered by Pedersen. That is, it is considered a reasonable hueristic to use it in place of a random oracle used for a security proof.
We employ the standard implementation of the Blake2s hash, which is fully documented here.
The Blake2s hash is utilized for computing nullifiers and for generating pseudorandom challenges, when verifying Schnorr signatures and when recursively verifying Plonk proofs.
Pedersen Hash 'h' Elements
There are additionally elliptic curve group points used in the computation of Pedersen hashes.
For example:
- : used to compute hashes for large data strings with inputs of size
- are used for all Pedersen Hashes in the Note Tree and Nullifier Tree
The generator algorithm for computing the in pseudocode is:
counter = 0
h = []
do
{
compute x = keccak256(pad(i)), pad(i) = 32-byte pad of i
find y = sqrt (x³ + ax + b))
if y = error
{
\\ unsuccessful: point does not exist (50% chance)
}
else
{
\\ successful: point exists and add to list (50% chance)
set h[counter] = (x, y)
}
counter = counter + 1
}
while counter < 1024