dragoonfri 0.1.0

Fast Reed-solomon Interactive oracle proof of proximity
Documentation
use ark_serialize::{CanonicalDeserialize, CanonicalSerialize};
use dragoonfri_test_utils::{
    do_for_multiple_folding_factors, Fq, BLOWUP_FACTOR, DOMAIN_SIZE, NUMBER_OF_POLYNOMIALS,
    NUM_QUERIES, POLY_COEFFS_LEN,
};
use rand::{thread_rng, Rng};
use winter_math::{fields::f128::BaseElement, FieldElement, StarkField};
use winter_rand_utils::{rand_value, rand_vector};
use winter_utils::transpose_slice;

use crate::{
    algorithms::Blake3,
    build_proof, commit_polynomial,
    folding::{reduce_polynomial, FoldedEvaluations},
    rng::FriChallenger,
    utils::to_evaluations,
    FriProof,
};

// This assumes winterfri is correct
#[test]
fn test_reduction() {
    for i in 0..NUMBER_OF_POLYNOMIALS {
        println!("    Testing on polynomial {i} / {NUMBER_OF_POLYNOMIALS}");

        let poly = rand_vector(POLY_COEFFS_LEN);
        let poly2 = convert_many(&poly);

        do_for_multiple_folding_factors!(FACTOR = 2, 4, 8, 16 => {
            println!("        --Folding factor={FACTOR}");
            let mut evaluations = prepare_winterfell_poly(poly.clone());
            let mut evaluations2 = to_evaluations(poly2.clone(), DOMAIN_SIZE);
            assert_eq!(convert_many(&evaluations), evaluations2);

            while evaluations.len() > FACTOR {
                let alpha = rand_value();
                let alpha2 = convert(&alpha);

                let transposed = transpose_slice::<_, FACTOR>(&evaluations);
                evaluations = winter_fri::folding::apply_drp(&transposed, BaseElement::ONE, alpha);
                let folded = FoldedEvaluations::new(&evaluations2);
                evaluations2 = reduce_polynomial::<FACTOR, _>(&folded, alpha2, None);

                assert_eq!(convert_many(&evaluations), evaluations2);
            }
        });
    }
}

#[test]
fn test_prove_verify() {
    let mut rng = thread_rng();
    let poly: Vec<Fq> = (0..POLY_COEFFS_LEN).map(|_| rng.gen()).collect();

    do_for_multiple_folding_factors!(FACTOR = 2, 4, 8, 16 => {
        println!("    --Folding factor={FACTOR}");

        let mut rng = FriChallenger::<Blake3>::default();
        let commitments = commit_polynomial::<FACTOR, _, Blake3, _>(poly.clone(), &mut rng, BLOWUP_FACTOR, 1);
        let proof = build_proof(commitments, &mut rng, NUM_QUERIES);

        rng.reset();
        assert!(proof.verify::<FACTOR, _>(rng.clone(), NUM_QUERIES, POLY_COEFFS_LEN, DOMAIN_SIZE).is_ok());

        assert!(proof.verify::<{FACTOR*2}, _>(rng.clone(), NUM_QUERIES, POLY_COEFFS_LEN, DOMAIN_SIZE).is_err());
        assert!(proof.verify::<{FACTOR/2}, _>(rng.clone(), NUM_QUERIES, POLY_COEFFS_LEN, DOMAIN_SIZE).is_err());

        assert!(proof.verify::<FACTOR, _>(rng.clone(), NUM_QUERIES, POLY_COEFFS_LEN, DOMAIN_SIZE * 2).is_err());
        assert!(proof.verify::<FACTOR, _>(rng.clone(), NUM_QUERIES, POLY_COEFFS_LEN, DOMAIN_SIZE / 2).is_err());

        assert!(proof.verify::<FACTOR, _>(rng.clone(), NUM_QUERIES, POLY_COEFFS_LEN / 2, DOMAIN_SIZE).is_err());

    });
}

#[test]
fn test_serialization() {
    let mut rng = thread_rng();
    let poly: Vec<Fq> = (0..POLY_COEFFS_LEN).map(|_| rng.gen()).collect();

    do_for_multiple_folding_factors!(FACTOR = 2, 4, 8, 16 => {
        println!("    --Folding factor={FACTOR}");

        let mut rng = FriChallenger::<Blake3>::default();
        let commitments = commit_polynomial::<FACTOR, _, Blake3, _>(poly.clone(), &mut rng, BLOWUP_FACTOR, 1);
        let proof = build_proof(commitments, &mut rng, NUM_QUERIES);

        let mut proof_bytes = vec![];
        proof.serialize_compressed(&mut proof_bytes).unwrap();

        let proof2 = FriProof::deserialize_compressed(&proof_bytes[..]).unwrap();
        assert_eq!(proof, proof2);

        rng.reset();
        proof2.verify::<FACTOR, _>(rng, NUM_QUERIES, POLY_COEFFS_LEN, DOMAIN_SIZE).unwrap();
    });
}

fn prepare_winterfell_poly<F: StarkField>(mut poly: Vec<F>) -> Vec<F> {
    use winter_math::fft::{evaluate_poly, get_twiddles};
    poly.resize(DOMAIN_SIZE, F::ZERO);
    let twiddles = get_twiddles(DOMAIN_SIZE);
    evaluate_poly(&mut poly, &twiddles);
    poly
}

fn convert(value: &BaseElement) -> Fq {
    Fq::from(value.as_int())
}

fn convert_many(values: &[BaseElement]) -> Vec<Fq> {
    values.iter().map(convert).collect()
}