This implementation leverages Poseidon2 hash function for both hashing columns and Merkle tree. It also leverages KoalaBear prime field. The field, hash and DFT implementations are taken from Plonky3 repository.
The original paper can be found here.
The following parameters have to be set up:
pub struct VortexParams {
perm: PoseidonHash,
nb_row: usize,
nb_col: usize,
rs_rate: usize,
num_columns_to_open: usize,
}
For example:
let params = VortexParams {
perm, // An instance of PoseidonHash
nb_row: 1 << 19, // Number of rows in commitment matrix
nb_col: 1 << 11, // Number of columns or a polynomial degree
rs_rate: 2, // Reed-Solomon code rate
num_columns_to_open: 256, // Number of columns to open in the opening phase
};
Use the following functions to commit/evaluate/open and verify:
- Commit
pub fn commit(params: &VortexParams, w: Vec<Vec<KoalaBear>>) -> (MerkleTree, Vec<Vec<KoalaBear>>)
- Eval
pub fn eval(params: &VortexParams, w: &Vec<Vec<KoalaBear>>, coin: KoalaBearExt, ) -> Vec<KoalaBearExt>
- Open
pub fn open(params: &VortexParams, w: &Vec<Vec<KoalaBear>>, w_: &Vec<Vec<KoalaBear>>, mt: &MerkleTree, beta: KoalaBearExt, column_ids: Vec<usize>) -> OpenProof
- Verify proof
pub fn verify(params: &VortexParams, proof: OpenProof, root: Digest, y: Vec<KoalaBearExt>, coin: KoalaBearExt)
The verification function asserts if proof is invalid. The implementation is fixed over KoalaBear field and its 4-degree extension. Check tests in lib.rs for more details.
Run command:
cargo test test_vortex_full --features nightly-features --release -- --show-output
The following benches are taken on the M3 Pro 36GB MakBook comparing to the Golang implementation (if changed to Poseidon2) from gnark-crypto
All tests are performed for
Gnark (sec) | Rust (sec) | |
---|---|---|
Commit | 70-75 | 31-35 |
Open Proof | 2 | 1.1-1.5 |
Verify | 28 | 1.6-1.7 |
Imagine we have a list of polynomials
For simplicity, let's define the interpolation function
Then, we organize these vectors into the matrix
We extend our matrix with additional columns by replacing each word
Then we hash each column, receiving
Given input
- The verifier samples a challenge
$\beta$ - The prover responds with
$u = B\cdot W$ , where$B = (1, \beta, \beta^1,\dots,\beta^{k-1})$ . Note that naturally, each element in$u$ equals to the sum of corresponding polynomials' coefficients over corresponding weight -- polynomial$i$ will be multiplied by$\beta^i$ . - Then, the verifier samples
$t$ indexes$q_1,\dots,q_t$ where$q_i \in [m]$ - The prover opens the corresponding columns
$s_1,\dots,s_t$ from the matrix$W'$ - The verifier computes the Reed-Solomon encoding of
$u$ named$u'$ . - The verifier checks:
-
$hash(s_i) == h_{q_i}$ for each$i\in [t]$ -
$B\cdot s_i == u'_{q_i}$ → this follows from the linearity of Reed-Solomon
-
- The verifier checks that
$Int_u(x) = B\cdot y$ . This check follows from the following observation:$a\cdot Int_c(x) = Int_{a\cdot c}(x)$ , so:-
$1 \cdot Int_{w_0}(x) = 1 \cdot y_0$ →$Int_{u_0}(x) = 1 \cdot y_1$ -
$\beta \cdot Int_{w_1}(x) = \beta \cdot y_1$ →$Int_{u_1}(x) = \beta \cdot y_1$ -
$\beta^2 \cdot Int_{w_2}(x) = \beta^2 \cdot y_2$ →$Int_{u_2}(x) = \beta^2 \cdot y_2$ - etc.
-
The parameter