// Copyright (c) Facebook, Inc. and its affiliates.
//
// This source code is licensed under the MIT license found in the
// LICENSE file in the root directory of this source tree.

use super::{flatten_slice_elements, DeserializationError, Vec};

mod byte_reader;
pub use byte_reader::{ByteReader, SliceReader};

mod byte_writer;
pub use byte_writer::ByteWriter;

// SERIALIZABLE TRAIT
// ================================================================================================

/// Defines how to serialize `Self` into bytes.
pub trait Serializable: Sized {
    // REQUIRED METHODS
    // --------------------------------------------------------------------------------------------
    /// Serializes `self` into bytes and writes these bytes into the `target`.
    fn write_into<W: ByteWriter>(&self, target: &mut W);

    // PROVIDED METHODS
    // --------------------------------------------------------------------------------------------

    /// Serializes `self` into a vector of bytes.
    fn to_bytes(&self) -> Vec<u8> {
        let mut result = Vec::with_capacity(self.get_size_hint());
        self.write_into(&mut result);
        result
    }

    /// Serializes all elements of the `source` and writes these bytes into the `target`.
    ///
    /// This method does not write any metadata (e.g. number of serialized elements) into the
    /// `target`.
    fn write_batch_into<W: ByteWriter>(source: &[Self], target: &mut W) {
        for item in source {
            item.write_into(target);
        }
    }

    /// Returns an estimate of how many bytes are needed to represent self.
    ///
    /// The default implementation returns zero.
    fn get_size_hint(&self) -> usize {
        0
    }
}

impl Serializable for () {
    fn write_into<W: ByteWriter>(&self, _target: &mut W) {}
}

impl<T: Serializable> Serializable for Vec<T> {
    fn write_into<W: ByteWriter>(&self, target: &mut W) {
        T::write_batch_into(self, target);
    }
}

impl<T: Serializable> Serializable for &Vec<T> {
    fn write_into<W: ByteWriter>(&self, target: &mut W) {
        T::write_batch_into(self, target);
    }
}

impl<T: Serializable, const N: usize> Serializable for Vec<[T; N]> {
    fn write_into<W: ByteWriter>(&self, target: &mut W) {
        let source = flatten_slice_elements(self);
        T::write_batch_into(source, target);
    }
}

impl<T: Serializable, const N: usize> Serializable for &Vec<[T; N]> {
    fn write_into<W: ByteWriter>(&self, target: &mut W) {
        let source = flatten_slice_elements(self);
        T::write_batch_into(source, target);
    }
}

impl<T: Serializable> Serializable for &[T] {
    fn write_into<W: ByteWriter>(&self, target: &mut W) {
        T::write_batch_into(self, target);
    }
}

impl<T: Serializable, const N: usize> Serializable for &[[T; N]] {
    fn write_into<W: ByteWriter>(&self, target: &mut W) {
        let source = flatten_slice_elements(self);
        T::write_batch_into(source, target);
    }
}

// DESERIALIZABLE
// ================================================================================================

/// Defines how to deserialize `Self` from bytes.
pub trait Deserializable: Sized {
    // REQUIRED METHODS
    // --------------------------------------------------------------------------------------------

    /// Reads a sequence of bytes from the provided `source`, attempts to deserialize these bytes
    /// into `Self`, and returns the result.
    ///
    /// # Errors
    /// Returns an error if:
    /// * The `source` does not contain enough bytes to deserialize `Self`.
    /// * Bytes read from the `source` do not represent a valid value for `Self`.
    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError>;

    // PROVIDED METHODS
    // --------------------------------------------------------------------------------------------

    /// Attempts to deserialize the provided `bytes` into `Self` and returns the result.
    ///
    /// # Errors
    /// Returns an error if:
    /// * The `bytes` do not contain enough information to deserialize `Self`.
    /// * The `bytes` do not represent a valid value for `Self`.
    ///
    /// Note: if `bytes` contains more data than needed to deserialize `self`, no error is
    /// returned.
    fn read_from_bytes(bytes: &[u8]) -> Result<Self, DeserializationError> {
        Self::read_from(&mut SliceReader::new(bytes))
    }

    /// Reads a sequence of bytes from the provided `source`, attempts to deserialize these bytes
    /// into a vector with the specified number of `Self` elements, and returns the result.
    ///
    /// # Errors
    /// Returns an error if:
    /// * The `source` does not contain enough bytes to deserialize the specified number of
    ///   elements.
    /// * Bytes read from the `source` do not represent a valid value for `Self` for any of the
    ///   elements.
    ///
    /// Note: if the error occurs, the reader is not rolled back to the state prior to calling
    /// this function.
    fn read_batch_from<R: ByteReader>(
        source: &mut R,
        num_elements: usize,
    ) -> Result<Vec<Self>, DeserializationError> {
        let mut result = Vec::with_capacity(num_elements);
        for _ in 0..num_elements {
            let element = Self::read_from(source)?;
            result.push(element)
        }
        Ok(result)
    }
}


// Copyright (c) Facebook, Inc. and its affiliates.
//
// This source code is licensed under the MIT license found in the
// LICENSE file in the root directory of this source tree.

//! This crates contains functions for generating random values.
//!
//! These functions are intended to be used in tests, benchmarks, and examples. When compiled to
//! WebAssembly target, all of the functions are omitted.

pub use internal::*;

#[cfg(not(target_family = "wasm"))]
mod internal {
    use core::{convert::TryInto, fmt::Debug};
    use rand::prelude::*;
    use utils::Randomizable;

    // RANDOM VALUE GENERATION
    // ============================================================================================

    /// Returns a single random value of the specified type.
    ///
    /// # Panics
    /// Panics if:
    /// * A valid value requires over 32 bytes.
    /// * A valid value could not be generated after 1000 tries.
    pub fn rand_value<R: Randomizable>() -> R {
        for _ in 0..1000 {
            let bytes = rand::thread_rng().gen::<[u8; 32]>();
            if let Some(value) = R::from_random_bytes(&bytes[..R::VALUE_SIZE]) {
                return value;
            }
        }

        panic!("failed generate a random field element");
    }

    /// Returns a vector of random value of the specified type and the specified length.
    ///
    /// # Panics
    /// Panics if:
    /// * A valid value requires at over 32 bytes.
    /// * A valid value could not be generated after 1000 tries.
    pub fn rand_vector<R: Randomizable>(n: usize) -> Vec<R> {
        let mut result = Vec::with_capacity(n);
        let seed = rand::thread_rng().gen::<[u8; 32]>();
        let mut g = StdRng::from_seed(seed);
        for _ in 0..1000 * n {
            let bytes = g.gen::<[u8; 32]>();
            if let Some(element) = R::from_random_bytes(&bytes[..R::VALUE_SIZE]) {
                result.push(element);
                if result.len() == n {
                    return result;
                }
            }
        }

        panic!("failed to generate enough random field elements");
    }

    /// Returns an array of random value of the specified type and the specified length.
    ///
    /// # Panics
    /// Panics if:
    /// * A valid value requires at over 32 bytes.
    /// * A valid value could not be generated after 1000 tries.
    pub fn rand_array<R: Randomizable + Debug, const N: usize>() -> [R; N] {
        let elements = rand_vector(N);
        elements
            .try_into()
            .expect("failed to convert vector to array")
    }

    /// Returns a vector of value of the specified type and the specified length generated
    /// pseudo-randomly from the specified `seed`.
    ///
    /// # Panics
    /// Panics if:
    /// * A valid value requires at over 32 bytes.
    /// * A valid value could not be generated after 1000 tries.
    pub fn prng_vector<R: Randomizable>(seed: [u8; 32], n: usize) -> Vec<R> {
        let mut result = Vec::with_capacity(n);
        let mut g = StdRng::from_seed(seed);
        for _ in 0..1000 * n {
            let bytes = g.gen::<[u8; 32]>();
            if let Some(element) = R::from_random_bytes(&bytes[..R::VALUE_SIZE]) {
                result.push(element);
                if result.len() == n {
                    return result;
                }
            }
        }

        panic!("failed to generate enough random field elements");
    }

    /// Returns an array of value of the specified type and the specified length generated
    /// pseudo-randomly from the specified `seed`.
    ///
    /// # Panics
    /// Panics if:
    /// * A valid value requires at over 32 bytes.
    /// * A valid value could not be generated after 1000 tries.
    pub fn prng_array<R: Randomizable + Debug, const N: usize>(seed: [u8; 32]) -> [R; N] {
        let elements = prng_vector(seed, N);
        elements
            .try_into()
            .expect("failed to convert vector to array")
    }

    // SHUFFLING
    // ============================================================================================

    /// Randomly shuffles slice elements.
    pub fn shuffle<T>(values: &mut [T]) {
        values.shuffle(&mut thread_rng());
    }
}

#[cfg(target_family = "wasm")]
mod internal {}

// TESTS
// ================================================================================================

#[cfg(test)]
mod tests {
    use super::{rand_array, rand_value};

    #[test]
    fn rand_primitives() {
        let a = rand_value::<u16>();
        let b = rand_value::<u16>();
        assert_ne!(a, b);

        let a = rand_value::<u32>();
        let b = rand_value::<u32>();
        assert_ne!(a, b);

        let a = rand_value::<u64>();
        let b = rand_value::<u64>();
        assert_ne!(a, b);

        let a = rand_value::<u128>();
        let b = rand_value::<u128>();
        assert_ne!(a, b);
    }

    #[test]
    fn rand_byte_array() {
        let a = rand_array::<u8, 30>();
        let b = rand_array::<u8, 30>();
        assert_ne!(a, b);

        let a = rand_array::<u8, 32>();
        let b = rand_array::<u8, 32>();
        assert_ne!(a, b);

        let a = rand_array::<u8, 34>();
        let b = rand_array::<u8, 34>();
        assert_ne!(a, b);
    }
}


// Copyright (c) Facebook, Inc. and its affiliates.
//
// This source code is licensed under the MIT license found in the
// LICENSE file in the root directory of this source tree.

use crate::VerifierError;
use air::{
    proof::{Queries, StarkProof, Table},
    Air, EvaluationFrame,
};
use crypto::{BatchMerkleProof, ElementHasher, MerkleTree};
use fri::VerifierChannel as FriVerifierChannel;
use math::{FieldElement, StarkField};
use utils::{collections::Vec, string::ToString};

// VERIFIER CHANNEL
// ================================================================================================

/// A view into a [StarkProof] for a computation structured to simulate an "interactive" channel.
///
/// A channel is instantiated for a specific proof, which is parsed into structs over the
/// appropriate field (specified by type parameter `E`). This also validates that the proof is
/// well-formed in the context of the computation for the specified [Air].
pub struct VerifierChannel<E: FieldElement, H: ElementHasher<BaseField = E::BaseField>> {
    // trace queries
    trace_roots: Vec<H::Digest>,
    trace_queries: Option<TraceQueries<E, H>>,
    // constraint queries
    constraint_root: H::Digest,
    constraint_queries: Option<ConstraintQueries<E, H>>,
    // FRI proof
    fri_roots: Option<Vec<H::Digest>>,
    fri_layer_proofs: Vec<BatchMerkleProof<H>>,
    fri_layer_queries: Vec<Vec<E>>,
    fri_remainder: Option<Vec<E>>,
    fri_num_partitions: usize,
    // out-of-domain frame
    ood_trace_frame: Option<TraceOodFrame<E>>,
    ood_constraint_evaluations: Option<Vec<E>>,
    // query proof-of-work
    pow_nonce: u64,
}

impl<E: FieldElement, H: ElementHasher<BaseField = E::BaseField>> VerifierChannel<E, H> {
    // CONSTRUCTOR
    // --------------------------------------------------------------------------------------------
    /// Creates and returns a new [VerifierChannel] initialized from the specified `proof`.
    pub fn new<A: Air<BaseField = E::BaseField>>(
        air: &A,
        proof: StarkProof,
    ) -> Result<Self, VerifierError> {
        let StarkProof {
            context,
            commitments,
            trace_queries,
            constraint_queries,
            ood_frame,
            fri_proof,
            pow_nonce,
        } = proof;

        // make sure AIR and proof base fields are the same
        if E::BaseField::get_modulus_le_bytes() != context.field_modulus_bytes() {
            return Err(VerifierError::InconsistentBaseField);
        }
        let constraint_frame_width = air.context().num_constraint_composition_columns();

        let num_trace_segments = air.trace_layout().num_segments();
        let main_trace_width = air.trace_layout().main_trace_width();
        let aux_trace_width = air.trace_layout().aux_trace_width();
        let lde_domain_size = air.lde_domain_size();
        let fri_options = air.options().to_fri_options();

        // --- parse commitments ------------------------------------------------------------------
        let (trace_roots, constraint_root, fri_roots) = commitments
            .parse::<H>(
                num_trace_segments,
                fri_options.num_fri_layers(lde_domain_size),
            )
            .map_err(|err| VerifierError::ProofDeserializationError(err.to_string()))?;

        // --- parse trace and constraint queries -------------------------------------------------
        let trace_queries = TraceQueries::new(trace_queries, air)?;
        let constraint_queries = ConstraintQueries::new(constraint_queries, air)?;

        // --- parse FRI proofs -------------------------------------------------------------------
        let fri_num_partitions = fri_proof.num_partitions();
        let fri_remainder = fri_proof
            .parse_remainder()
            .map_err(|err| VerifierError::ProofDeserializationError(err.to_string()))?;
        let (fri_layer_queries, fri_layer_proofs) = fri_proof
            .parse_layers::<H, E>(lde_domain_size, fri_options.folding_factor())
            .map_err(|err| VerifierError::ProofDeserializationError(err.to_string()))?;

        // --- parse out-of-domain evaluation frame -----------------------------------------------
        let (ood_trace_evaluations, ood_constraint_evaluations) = ood_frame
            .parse(main_trace_width, aux_trace_width, constraint_frame_width)
            .map_err(|err| VerifierError::ProofDeserializationError(err.to_string()))?;
        let ood_trace_frame =
            TraceOodFrame::new(ood_trace_evaluations, main_trace_width, aux_trace_width);

        Ok(VerifierChannel {
            // trace queries
            trace_roots,
            trace_queries: Some(trace_queries),
            // constraint queries
            constraint_root,
            constraint_queries: Some(constraint_queries),
            // FRI proof
            fri_roots: Some(fri_roots),
            fri_layer_proofs,
            fri_layer_queries,
            fri_remainder: Some(fri_remainder),
            fri_num_partitions,
            // out-of-domain evaluation
            ood_trace_frame: Some(ood_trace_frame),
            ood_constraint_evaluations: Some(ood_constraint_evaluations),
            // query seed
            pow_nonce,
        })
    }

    // DATA READERS
    // --------------------------------------------------------------------------------------------

    /// Returns execution trace commitments sent by the prover.
    ///
    /// For computations requiring multiple trace segment, the returned slice will contain a
    /// commitment for each trace segment.
    pub fn read_trace_commitments(&self) -> &[H::Digest] {
        &self.trace_roots
    }

    /// Returns constraint evaluation commitment sent by the prover.
    pub fn read_constraint_commitment(&self) -> H::Digest {
        self.constraint_root
    }

    /// Returns trace polynomial evaluations at out-of-domain points z and z * g, where g is the
    /// generator of the LDE domain.
    ///
    /// For computations requiring multiple trace segments, evaluations of auxiliary trace
    /// polynomials are also included.
    pub fn read_ood_trace_frame(&mut self) -> TraceOodFrame<E> {
        self.ood_trace_frame.take().expect("already read")
    }

    /// Returns evaluations of composition polynomial columns at z^m, where z is the out-of-domain
    /// point, and m is the number of composition polynomial columns.
    pub fn read_ood_constraint_evaluations(&mut self) -> Vec<E> {
        self.ood_constraint_evaluations
            .take()
            .expect("already read")
    }

    /// Returns query proof-of-work nonce sent by the prover.
    pub fn read_pow_nonce(&self) -> u64 {
        self.pow_nonce
    }

    /// Returns trace states at the specified positions of the LDE domain. This also checks if
    /// the trace states are valid against the trace commitment sent by the prover.
    ///
    /// For computations requiring multiple trace segments, trace states for auxiliary segments
    /// are also included as the second value of the returned tuple (trace states for all auxiliary
    /// segments are merged into a single table). Otherwise, the second value is None.
    #[allow(clippy::type_complexity)]
    pub fn read_queried_trace_states(
        &mut self,
        positions: &[usize],
    ) -> Result<(Table<E::BaseField>, Option<Table<E>>), VerifierError> {
        let queries = self.trace_queries.take().expect("already read");

        // make sure the states included in the proof correspond to the trace commitment
        for (root, proof) in self.trace_roots.iter().zip(queries.query_proofs.iter()) {
            MerkleTree::verify_batch(root, positions, proof)
                .map_err(|_| VerifierError::TraceQueryDoesNotMatchCommitment)?;
        }

        Ok((queries.main_states, queries.aux_states))
    }

    /// Returns constraint evaluations at the specified positions of the LDE domain. This also
    /// checks if the constraint evaluations are valid against the constraint commitment sent by
    /// the prover.
    pub fn read_constraint_evaluations(
        &mut self,
        positions: &[usize],
    ) -> Result<Table<E>, VerifierError> {
        let queries = self.constraint_queries.take().expect("already read");

        MerkleTree::verify_batch(&self.constraint_root, positions, &queries.query_proofs)
            .map_err(|_| VerifierError::ConstraintQueryDoesNotMatchCommitment)?;

        Ok(queries.evaluations)
    }
}

// FRI VERIFIER CHANNEL IMPLEMENTATION
// ================================================================================================

impl<E, H> FriVerifierChannel<E> for VerifierChannel<E, H>
where
    E: FieldElement,
    H: ElementHasher<BaseField = E::BaseField>,
{
    type Hasher = H;

    fn read_fri_num_partitions(&self) -> usize {
        self.fri_num_partitions
    }

    fn read_fri_layer_commitments(&mut self) -> Vec<H::Digest> {
        self.fri_roots.take().expect("already read")
    }

    fn take_next_fri_layer_proof(&mut self) -> BatchMerkleProof<H> {
        self.fri_layer_proofs.remove(0)
    }

    fn take_next_fri_layer_queries(&mut self) -> Vec<E> {
        self.fri_layer_queries.remove(0)
    }

    fn take_fri_remainder(&mut self) -> Vec<E> {
        self.fri_remainder.take().expect("already read")
    }
}

// TRACE QUERIES
// ================================================================================================

/// Container of trace query data, including:
/// * Queried states for all trace segments.
/// * Merkle authentication paths for all queries.
///
/// Trace states for all auxiliary segments are stored in a single table.
struct TraceQueries<E: FieldElement, H: ElementHasher<BaseField = E::BaseField>> {
    query_proofs: Vec<BatchMerkleProof<H>>,
    main_states: Table<E::BaseField>,
    aux_states: Option<Table<E>>,
}

impl<E: FieldElement, H: ElementHasher<BaseField = E::BaseField>> TraceQueries<E, H> {
    /// Parses the provided trace queries into trace states in the specified field and
    /// corresponding Merkle authentication paths.
    pub fn new<A: Air<BaseField = E::BaseField>>(
        mut queries: Vec<Queries>,
        air: &A,
    ) -> Result<Self, VerifierError> {
        assert_eq!(
            queries.len(),
            air.trace_layout().num_segments(),
            "expected {} trace segment queries, but received {}",
            air.trace_layout().num_segments(),
            queries.len()
        );

        let num_queries = air.options().num_queries();

        // parse main trace segment queries; parsing also validates that hashes of each table row
        // form the leaves of Merkle authentication paths in the proofs
        let main_segment_width = air.trace_layout().main_trace_width();
        let main_segment_queries = queries.remove(0);
        let (main_segment_query_proofs, main_segment_states) = main_segment_queries
            .parse::<H, E::BaseField>(air.lde_domain_size(), num_queries, main_segment_width)
            .map_err(|err| {
                VerifierError::ProofDeserializationError(format!(
                    "main trace segment query deserialization failed: {err}"
                ))
            })?;

        // all query proofs will be aggregated into a single vector
        let mut query_proofs = vec![main_segment_query_proofs];

        // parse auxiliary trace segment queries (if any), and merge resulting tables into a
        // single table; parsing also validates that hashes of each table row form the leaves
        // of Merkle authentication paths in the proofs
        let aux_trace_states = if air.trace_info().is_multi_segment() {
            let mut aux_trace_states = Vec::new();
            for (i, segment_queries) in queries.into_iter().enumerate() {
                let segment_width = air.trace_layout().get_aux_segment_width(i);
                let (segment_query_proof, segment_trace_states) = segment_queries
                    .parse::<H, E>(air.lde_domain_size(), num_queries, segment_width)
                    .map_err(|err| {
                        VerifierError::ProofDeserializationError(format!(
                            "auxiliary trace segment query deserialization failed: {err}"
                        ))
                    })?;

                query_proofs.push(segment_query_proof);
                aux_trace_states.push(segment_trace_states);
            }

            // merge tables for each auxiliary segment into a single table
            Some(Table::merge(aux_trace_states))
        } else {
            None
        };

        Ok(Self {
            query_proofs,
            main_states: main_segment_states,
            aux_states: aux_trace_states,
        })
    }
}

// CONSTRAINT QUERIES
// ================================================================================================

/// Container of constraint evaluation query data, including:
/// * Queried constraint evaluation values.
/// * Merkle authentication paths for all queries.
struct ConstraintQueries<E: FieldElement, H: ElementHasher<BaseField = E::BaseField>> {
    query_proofs: BatchMerkleProof<H>,
    evaluations: Table<E>,
}

impl<E: FieldElement, H: ElementHasher<BaseField = E::BaseField>> ConstraintQueries<E, H> {
    /// Parses the provided constraint queries into evaluations in the specified field and
    /// corresponding Merkle authentication paths.
    pub fn new<A: Air<BaseField = E::BaseField>>(
        queries: Queries,
        air: &A,
    ) -> Result<Self, VerifierError> {
        let num_queries = air.options().num_queries();
        let constraint_frame_width = air.context().num_constraint_composition_columns();

        let (query_proofs, evaluations) = queries
            .parse::<H, E>(air.lde_domain_size(), num_queries, constraint_frame_width)
            .map_err(|err| {
                VerifierError::ProofDeserializationError(format!(
                    "constraint evaluation query deserialization failed: {err}"
                ))
            })?;

        Ok(Self {
            query_proofs,
            evaluations,
        })
    }
}

// TRACE OUT-OF-DOMAIN FRAME
// ================================================================================================

pub struct TraceOodFrame<E: FieldElement> {
    values: Vec<E>,
    main_trace_width: usize,
    aux_trace_width: usize,
}

impl<E: FieldElement> TraceOodFrame<E> {
    pub fn new(values: Vec<E>, main_trace_width: usize, aux_trace_width: usize) -> Self {
        Self {
            values,
            main_trace_width,
            aux_trace_width,
        }
    }

    pub fn values(&self) -> &[E] {
        &self.values
    }

    // The out-of-domain frame is stored as one vector of interleaved values, one from the
    // current row and the other from the next row. See `OodFrame::set_trace_states`.
    // Thus we need to untangle the current and next rows stored in `Self::values` and we
    // do that for the main and auxiliary traces separately.
    // Pictorially, for the main trace portion:
    //
    // Input vector: [a1, b1, a2, b2, ..., an, bn, c1, d1, c2, d2, ..., cm, dm]
    // with n being the main trace width and m the auxiliary trace width.
    //
    // Output:
    //          +-------+-------+-------+-------+-------+
    //          |  a1   |   a2  |   a3  |  ...  |   an  |
    //          +-------+-------+-------+-------+-------+
    //          |  b1   |   b2  |   b3  |  ...  |   bn  |
    //          +-------+-------+-------+-------+-------+
    pub fn main_frame(&self) -> EvaluationFrame<E> {
        let mut current = vec![E::ZERO; self.main_trace_width];
        let mut next = vec![E::ZERO; self.main_trace_width];

        for (i, a) in self
            .values
            .chunks(2)
            .take(self.main_trace_width)
            .enumerate()
        {
            current[i] = a[0];
            next[i] = a[1];
        }

        EvaluationFrame::from_rows(current, next)
    }

    // Similar to `Self::main_frame`, the following untangles the current and next rows stored
    // in `Self::values` for the auxiliary trace portion when it exists else it returns `None`.
    // Pictorially:
    //
    // Input vector: [a1, b1, a2, b2, ..., an, bn, c1, d1, c2, d2, ..., cm, dm]
    // with n being the main trace width and m the auxiliary trace width.
    //
    // Output:
    //          +-------+-------+-------+-------+-------+
    //          |  c1   |   c2  |   c3  |  ...  |   cm  |
    //          +-------+-------+-------+-------+-------+
    //          |  d1   |   d2  |   d3  |  ...  |   dm  |
    //          +-------+-------+-------+-------+-------+
    pub fn aux_frame(&self) -> Option<EvaluationFrame<E>> {
        if self.aux_trace_width == 0 {
            None
        } else {
            let mut current_aux = vec![E::ZERO; self.aux_trace_width];
            let mut next_aux = vec![E::ZERO; self.aux_trace_width];

            for (i, a) in self
                .values
                .chunks(2)
                .skip(self.main_trace_width)
                .enumerate()
            {
                current_aux[i] = a[0];
                next_aux[i] = a[1];
            }
            Some(EvaluationFrame::from_rows(current_aux, next_aux))
        }
    }
}


// Copyright (c) Facebook, Inc. and its affiliates.
//
// This source code is licensed under the MIT license found in the
// LICENSE file in the root directory of this source tree.

use air::{proof::Table, Air, DeepCompositionCoefficients, EvaluationFrame};
use math::{batch_inversion, FieldElement};
use utils::collections::Vec;

// DEEP COMPOSER
// ================================================================================================

pub struct DeepComposer<E: FieldElement> {
    cc: DeepCompositionCoefficients<E>,
    x_coordinates: Vec<E>,
    z: [E; 2],
}

impl<E: FieldElement> DeepComposer<E> {
    /// Creates a new composer for computing DEEP composition polynomial values.
    pub fn new<A: Air<BaseField = E::BaseField>>(
        air: &A,
        query_positions: &[usize],
        z: E,
        cc: DeepCompositionCoefficients<E>,
    ) -> Self {
        // compute LDE domain coordinates for all query positions
        let g_lde = air.lde_domain_generator();
        let domain_offset = air.domain_offset();
        let x_coordinates: Vec<E> = query_positions
            .iter()
            .map(|&p| E::from(g_lde.exp_vartime((p as u64).into()) * domain_offset))
            .collect();

        DeepComposer {
            cc,
            x_coordinates,
            z: [z, z * E::from(air.trace_domain_generator())],
        }
    }

    /// For each queried trace state, combines column values into a single value by computing
    /// their random linear combinations as follows:
    ///
    /// - Assume each column value is an evaluation of a trace polynomial T_i(x).
    /// - For each T_i(x) compute T'_i(x) = (T_i(x) - T_i(z)) / (x - z) and
    ///   T''_i = (T_i(x) - T_i(z * g)) / (x - z * g), where z is the out-of-domain point and
    ///   g is the the LDE domain generator.
    /// - Then, combine all T'_i(x) and T''_i(x) values together by computing
    ///   T(x) = sum((T'_i(x) + T''_i(x)) * cc_i) for all i, where cc_i is the coefficient for
    ///   for the random linear combination drawn from the public coin.
    ///
    /// Note that values of T_i(z) and T_i(z * g) are received from the prover and passed into
    /// this function via the `ood_main_frame` and `ood_aux_frame` parameters.
    pub fn compose_trace_columns(
        &self,
        queried_main_trace_states: Table<E::BaseField>,
        queried_aux_trace_states: Option<Table<E>>,
        ood_main_frame: EvaluationFrame<E>,
        ood_aux_frame: Option<EvaluationFrame<E>>,
    ) -> Vec<E> {
        let ood_main_trace_states = [ood_main_frame.current(), ood_main_frame.next()];

        // compose columns of of the main trace segment; we do this separately for numerators of
        // each query; we also track common denominator for each query separately; this way we can
        // use a batch inversion in the end.
        let n = queried_main_trace_states.num_rows();
        let mut result_num = Vec::<E>::with_capacity(n);
        let mut result_den = Vec::<E>::with_capacity(n);

        for ((_, row), &x) in (0..n)
            .zip(queried_main_trace_states.rows())
            .zip(&self.x_coordinates)
        {
            let mut t1_num = E::ZERO;
            let mut t2_num = E::ZERO;

            for (i, &value) in row.iter().enumerate() {
                let value = E::from(value);
                // compute the numerator of T'_i(x) as (T_i(x) - T_i(z)), multiply it by a
                // composition coefficient, and add the result to the numerator aggregator
                t1_num += (value - ood_main_trace_states[0][i]) * self.cc.trace[i];

                // compute the numerator of T''_i(x) as (T_i(x) - T_i(z * g)), multiply it by a
                // composition coefficient, and add the result to the numerator aggregator
                t2_num += (value - ood_main_trace_states[1][i]) * self.cc.trace[i];
            }
            // compute the common denominator as (x - z) * (x - z * g)
            let t1_den = x - self.z[0];
            let t2_den = x - self.z[1];
            result_den.push(t1_den * t2_den);

            // add the numerators of T'_i(x) and T''_i(x) together; we can do this because later on
            // we'll use the common denominator computed above.
            result_num.push(t1_num * t2_den + t2_num * t1_den);
        }

        // if the trace has auxiliary segments, compose columns from these segments as well; we
        // also do this separately for numerators and denominators.
        if let Some(queried_aux_trace_states) = queried_aux_trace_states {
            let ood_aux_frame = ood_aux_frame.expect("missing auxiliary OOD frame");
            let ood_aux_trace_states = [ood_aux_frame.current(), ood_aux_frame.next()];

            // we define this offset here because composition of the main trace columns has
            // consumed some number of composition coefficients already.
            let cc_offset = queried_main_trace_states.num_columns();

            for ((j, row), &x) in (0..n)
                .zip(queried_aux_trace_states.rows())
                .zip(&self.x_coordinates)
            {
                let mut t1_num = E::ZERO;
                let mut t2_num = E::ZERO;
                for (i, &value) in row.iter().enumerate() {
                    // compute the numerator of T'_i(x) as (T_i(x) - T_i(z)), multiply it by a
                    // composition coefficient, and add the result to the numerator aggregator
                    t1_num += (value - ood_aux_trace_states[0][i]) * self.cc.trace[cc_offset + i];

                    // compute the numerator of T''_i(x) as (T_i(x) - T_i(z * g)), multiply it by a
                    // composition coefficient, and add the result to the numerator aggregator
                    t2_num += (value - ood_aux_trace_states[1][i]) * self.cc.trace[cc_offset + i];
                }

                // compute the common denominators (x - z) and (x - z * g), and use the to aggregate
                // numerators into the common numerator computed for the main trace of this query
                let t1_den = x - self.z[0];
                let t2_den = x - self.z[1];
                result_num[j] += t1_num * t2_den + t2_num * t1_den;
            }
        }

        result_den = batch_inversion(&result_den);
        result_num
            .iter()
            .zip(result_den)
            .map(|(n, d)| *n * d)
            .collect()
    }

    /// For each queried set of composition polynomial column evaluations, combine evaluations
    /// into a single value by computing their random linear combination as follows:
    ///
    /// - Assume each queried value is an evaluation of a composition polynomial column H_i(x).
    /// - For each H_i(x), compute H'_i(x) = (H_i(x) - H(z)) / (x - z).
    /// - Then, combine all H_i(x) values together by computing H(x) = sum(H_i(x) * cc_i) for
    ///   all i, where cc_i is the coefficient for the random linear combination drawn from the
    ///   public coin.
    ///
    /// Note that values of H_i(z) are received from the prover and passed into this function
    /// via the `ood_evaluations` parameter.
    pub fn compose_constraint_evaluations(
        &self,
        queried_evaluations: Table<E>,
        ood_evaluations: Vec<E>,
    ) -> Vec<E> {
        assert_eq!(queried_evaluations.num_rows(), self.x_coordinates.len());

        let n = queried_evaluations.num_rows();
        let mut result_num = Vec::<E>::with_capacity(n);
        let mut result_den = Vec::<E>::with_capacity(n);

        let z = self.z[0];

        // combine composition polynomial columns separately for numerators and denominators;
        // this way we can use batch inversion in the end.
        for (query_values, &x) in queried_evaluations.rows().zip(&self.x_coordinates) {
            let mut composition_num = E::ZERO;
            for (i, &evaluation) in query_values.iter().enumerate() {
                // compute the numerator of H'_i(x) as (H_i(x) - H_i(z)), multiply it by a
                // composition coefficient, and add the result to the numerator aggregator
                composition_num += (evaluation - ood_evaluations[i]) * self.cc.constraints[i];
            }
            result_num.push(composition_num);
            result_den.push(x - z);
        }

        result_den = batch_inversion(&result_den);
        result_num
            .iter()
            .zip(result_den)
            .map(|(n, d)| *n * d)
            .collect()
    }

    /// Combines trace and constraint compositions together.
    #[rustfmt::skip]
    pub fn combine_compositions(&self, t_composition: Vec<E>, c_composition: Vec<E>) -> Vec<E> {
        assert_eq!(t_composition.len(), self.x_coordinates.len());
        assert_eq!(c_composition.len(), self.x_coordinates.len());

        let mut result = Vec::with_capacity(self.x_coordinates.len());
        for (t, c) in t_composition.iter().zip(c_composition) {
            // compute C(x) by adding the two compositions together
            result.push(*t + c);
        }

        result
    }
}


// Copyright (c) Facebook, Inc. and its affiliates.
//
// This source code is licensed under the MIT license found in the
// LICENSE file in the root directory of this source tree.

//! Contains common error types for prover and verifier.

use core::fmt;
use utils::string::String;

// VERIFIER ERROR
// ================================================================================================
/// Represents an error returned by the verifier during an execution of the protocol.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum VerifierError {
    /// This error occurs when base field read by a verifier from a proof does not match the
    /// base field of AIR with which the verifier was instantiated.
    InconsistentBaseField,
    /// This error occurs when the base field in which the proof was generated does not support
    /// field extension of degree specified by the proof.
    UnsupportedFieldExtension(usize),
    /// This error occurs when a verifier cannot deserialize the specified proof.
    ProofDeserializationError(String),
    /// This error occurs when a verifier fails to draw a random value from a random coin
    /// within a specified number of tries.
    RandomCoinError,
    /// This error occurs when constraints evaluated over out-of-domain trace rows do not match
    /// evaluations of the constraint composition polynomial at the out-of-domain point.
    InconsistentOodConstraintEvaluations,
    /// This error occurs when Merkle authentication paths of trace queries do not resolve to the
    /// execution trace commitment included in the proof.
    TraceQueryDoesNotMatchCommitment,
    /// This error occurs when Merkle authentication paths of constraint evaluation queries do not
    /// resolve to the constraint evaluation commitment included in the proof.
    ConstraintQueryDoesNotMatchCommitment,
    /// This error occurs when the proof-of-work nonce hashed with the current state of the public
    /// coin resolves to a value which does not meet the proof-of-work threshold specified by the
    // proof options.
    QuerySeedProofOfWorkVerificationFailed,
    /// This error occurs when the DEEP composition polynomial evaluations derived from trace and
    /// constraint evaluation queries do not represent a polynomial of the degree expected by the
    /// verifier.
    FriVerificationFailed(fri::VerifierError),
}

impl fmt::Display for VerifierError {
    #[rustfmt::skip]
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Self::InconsistentBaseField =>  {
                write!(f, "base field of the proof does not match base field of the specified AIR")
            }
            Self::UnsupportedFieldExtension(degree) => {
                write!(f, "field extension of degree {degree} is not supported for the proof base field")
            }
            Self::ProofDeserializationError(msg) => {
                write!(f, "proof deserialization failed: {msg}")
            }
            Self::RandomCoinError => {
                write!(f, "failed to draw a random value from a random coin")
            }
            Self::InconsistentOodConstraintEvaluations => {
                write!(f, "constraint evaluations over the out-of-domain frame are inconsistent")
            }
            Self::TraceQueryDoesNotMatchCommitment => {
                write!(f, "trace query did not match the commitment")
            }
            Self::ConstraintQueryDoesNotMatchCommitment => {
                write!(f, "constraint query did not match the commitment")
            }
            Self::QuerySeedProofOfWorkVerificationFailed => {
                write!(f, "query seed proof-of-work verification failed")
            }
            Self::FriVerificationFailed(err) => {
                write!(f, "verification of low-degree proof failed: {err}")
            }
        }
    }
}


// Copyright (c) Facebook, Inc. and its affiliates.
//
// This source code is licensed under the MIT license found in the
// LICENSE file in the root directory of this source tree.

use air::{Air, AuxTraceRandElements, ConstraintCompositionCoefficients, EvaluationFrame};
use math::{polynom, FieldElement};
use utils::collections::Vec;

// CONSTRAINT EVALUATION
// ================================================================================================

/// Evaluates constraints for the specified evaluation frame.
pub fn evaluate_constraints<A: Air, E: FieldElement<BaseField = A::BaseField>>(
    air: &A,
    composition_coefficients: ConstraintCompositionCoefficients<E>,
    main_trace_frame: &EvaluationFrame<E>,
    aux_trace_frame: &Option<EvaluationFrame<E>>,
    aux_rand_elements: AuxTraceRandElements<E>,
    x: E,
) -> E {
    // 1 ----- evaluate transition constraints ----------------------------------------------------

    // initialize a buffer to hold transition constraint evaluations
    let t_constraints = air.get_transition_constraints(&composition_coefficients.transition);

    // compute values of periodic columns at x
    let periodic_values = air
        .get_periodic_column_polys()
        .iter()
        .map(|poly| {
            let num_cycles = air.trace_length() / poly.len();
            let x = x.exp_vartime((num_cycles as u32).into());
            polynom::eval(poly, x)
        })
        .collect::<Vec<_>>();

    // evaluate transition constraints for the main trace segment
    let mut t_evaluations1 = E::zeroed_vector(t_constraints.num_main_constraints());
    air.evaluate_transition(main_trace_frame, &periodic_values, &mut t_evaluations1);

    // evaluate transition constraints for auxiliary trace segments (if any)
    let mut t_evaluations2 = E::zeroed_vector(t_constraints.num_aux_constraints());
    if let Some(aux_trace_frame) = aux_trace_frame {
        air.evaluate_aux_transition(
            main_trace_frame,
            aux_trace_frame,
            &periodic_values,
            &aux_rand_elements,
            &mut t_evaluations2,
        );
    }

    // merge all constraint evaluations into a single value by computing their random linear
    // combination using coefficients drawn from the public coin. this also divides the result
    // by the divisor of transition constraints.
    let mut result = t_constraints.combine_evaluations::<E>(&t_evaluations1, &t_evaluations2, x);

    // 2 ----- evaluate boundary constraints ------------------------------------------------------

    // get boundary constraints grouped by common divisor from the AIR
    let b_constraints =
        air.get_boundary_constraints(&aux_rand_elements, &composition_coefficients.boundary);

    // iterate over boundary constraint groups for the main trace segment (each group has a
    // distinct divisor), evaluate constraints in each group and add their combination to the
    // result
    for group in b_constraints.main_constraints().iter() {
        result += group.evaluate_at(main_trace_frame.current(), x);
    }

    // iterate over boundary constraint groups for auxiliary trace segments (each group has a
    // distinct divisor), evaluate constraints in each group and add their combination to the
    // result
    if let Some(aux_trace_frame) = aux_trace_frame {
        for group in b_constraints.aux_constraints().iter() {
            result += group.evaluate_at(aux_trace_frame.current(), x);
        }
    }

    result
}


// Copyright (c) Facebook, Inc. and its affiliates.
//
// This source code is licensed under the MIT license found in the
// LICENSE file in the root directory of this source tree.

//! This crate contains Winterfell STARK verifier.
//!
//! This verifier can be used to verify STARK proofs generated by the Winterfell STARK prover.
//!
//! # Usage
//! To verify a proof that a computation was executed correctly, you'll need to do the following:
//!
//! 1. Define an *algebraic intermediate representation* (AIR) for you computation. This can be
//!    done by implementing [Air] trait.
//! 2. Execute [verify()] function and supply the AIR of your computation together with the
//!    [StarkProof] and related public inputs as parameters.
//!
//! # Performance
//! Proof verification is extremely fast and is nearly independent of the complexity of the
//! computation being verified. In vast majority of cases proofs can be verified in 3 - 5 ms
//! on a modern mid-range laptop CPU (using a single core).
//!
//! There is one exception, however: if a computation requires a lot of `sequence` assertions
//! (see [Assertion] for more info), the verification time will grow linearly in the number of
//! asserted values. But for the impact to be noticeable, the number of asserted values would
//! need to be in tens of thousands. And even for hundreds of thousands of asserted values, the
//! verification time should not exceed 50 ms.

#![cfg_attr(not(feature = "std"), no_std)]

#[cfg(not(feature = "std"))]
#[macro_use]
extern crate alloc;

pub use air::{
    proof::StarkProof, Air, AirContext, Assertion, AuxTraceRandElements, BoundaryConstraint,
    BoundaryConstraintGroup, ConstraintCompositionCoefficients, ConstraintDivisor,
    DeepCompositionCoefficients, EvaluationFrame, FieldExtension, ProofOptions, TraceInfo,
    TransitionConstraintDegree,
};

pub use math;
use math::{
    fields::{CubeExtension, QuadExtension},
    FieldElement, ToElements,
};

pub use utils::{
    ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable, SliceReader,
};

pub use crypto;
use crypto::{ElementHasher, RandomCoin};

use fri::FriVerifier;

mod channel;
use channel::VerifierChannel;

mod evaluator;
use evaluator::evaluate_constraints;

mod composer;
use composer::DeepComposer;

mod errors;
pub use errors::VerifierError;

// VERIFIER
// ================================================================================================
/// Verifies that the specified computation was executed correctly against the specified inputs.
///
/// Specifically, for a computation specified by `AIR` and `HashFn` type parameter, verifies that the provided
/// `proof` attests to the correct execution of the computation against public inputs specified
/// by `pub_inputs`. If the verification is successful, `Ok(())` is returned.
///
/// # Errors
/// Returns an error if combination of the provided proof and public inputs does not attest to
/// a correct execution of the computation. This could happen for many various reasons, including:
/// - The specified proof was generated for a different computation.
/// - The specified proof was generated for this computation but for different public inputs.
#[rustfmt::skip]
pub fn verify<AIR, HashFn, RandCoin>(
    proof: StarkProof,
    pub_inputs: AIR::PublicInputs,
) -> Result<(), VerifierError>
where
    AIR: Air,
    HashFn: ElementHasher<BaseField = AIR::BaseField>,
    RandCoin: RandomCoin<BaseField = AIR::BaseField, Hasher = HashFn>,
{
    // build a seed for the public coin; the initial seed is a hash of the proof context and the
    // public inputs, but as the protocol progresses, the coin will be reseeded with the info
    // received from the prover
    let mut public_coin_seed = proof.context.to_elements();
    public_coin_seed.append(&mut pub_inputs.to_elements());

    // create AIR instance for the computation specified in the proof
    let air = AIR::new(proof.get_trace_info(), pub_inputs, proof.options().clone());

    // figure out which version of the generic proof verification procedure to run. this is a sort
    // of static dispatch for selecting two generic parameter: extension field and hash function.
    match air.options().field_extension() {
        FieldExtension::None => {
            let public_coin = RandCoin::new(&public_coin_seed);
            let channel = VerifierChannel::new(&air, proof)?;
            perform_verification::<AIR, AIR::BaseField, HashFn, RandCoin>(air, channel, public_coin)
        },
        FieldExtension::Quadratic => {
            if !<QuadExtension<AIR::BaseField>>::is_supported() {
                return Err(VerifierError::UnsupportedFieldExtension(2));
            }
            let public_coin = RandCoin::new(&public_coin_seed);
            let channel = VerifierChannel::new(&air, proof)?;
            perform_verification::<AIR, QuadExtension<AIR::BaseField>, HashFn, RandCoin>(air, channel, public_coin)
        },
        FieldExtension::Cubic => {
            if !<CubeExtension<AIR::BaseField>>::is_supported() {
                return Err(VerifierError::UnsupportedFieldExtension(3));
            }
            let public_coin = RandCoin::new(&public_coin_seed);
            let channel = VerifierChannel::new(&air, proof)?;
            perform_verification::<AIR, CubeExtension<AIR::BaseField>, HashFn, RandCoin>(air, channel, public_coin)
        },
    }
}

// VERIFICATION PROCEDURE
// ================================================================================================
/// Performs the actual verification by reading the data from the `channel` and making sure it
/// attests to a correct execution of the computation specified by the provided `air`.
fn perform_verification<A, E, H, R>(
    air: A,
    mut channel: VerifierChannel<E, H>,
    mut public_coin: R,
) -> Result<(), VerifierError>
where
    A: Air,
    E: FieldElement<BaseField = A::BaseField>,
    H: ElementHasher<BaseField = A::BaseField>,
    R: RandomCoin<BaseField = A::BaseField, Hasher = H>,
{
    // 1 ----- trace commitment -------------------------------------------------------------------
    // Read the commitments to evaluations of the trace polynomials over the LDE domain sent by the
    // prover. The commitments are used to update the public coin, and draw sets of random elements
    // from the coin (in the interactive version of the protocol the verifier sends these random
    // elements to the prover after each commitment is made). When there are multiple trace
    // commitments (i.e., the trace consists of more than one segment), each previous commitment is
    // used to draw random elements needed to construct the next trace segment. The last trace
    // commitment is used to draw a set of random coefficients which the prover uses to compute
    // constraint composition polynomial.
    let trace_commitments = channel.read_trace_commitments();

    // reseed the coin with the commitment to the main trace segment
    public_coin.reseed(trace_commitments[0]);

    // process auxiliary trace segments (if any), to build a set of random elements for each segment
    let mut aux_trace_rand_elements = AuxTraceRandElements::<E>::new();
    for (i, commitment) in trace_commitments.iter().skip(1).enumerate() {
        let rand_elements = air
            .get_aux_trace_segment_random_elements(i, &mut public_coin)
            .map_err(|_| VerifierError::RandomCoinError)?;
        aux_trace_rand_elements.add_segment_elements(rand_elements);
        public_coin.reseed(*commitment);
    }

    // build random coefficients for the composition polynomial
    let constraint_coeffs = air
        .get_constraint_composition_coefficients(&mut public_coin)
        .map_err(|_| VerifierError::RandomCoinError)?;

    // 2 ----- constraint commitment --------------------------------------------------------------
    // read the commitment to evaluations of the constraint composition polynomial over the LDE
    // domain sent by the prover, use it to update the public coin, and draw an out-of-domain point
    // z from the coin; in the interactive version of the protocol, the verifier sends this point z
    // to the prover, and the prover evaluates trace and constraint composition polynomials at z,
    // and sends the results back to the verifier.
    let constraint_commitment = channel.read_constraint_commitment();
    public_coin.reseed(constraint_commitment);
    let z = public_coin
        .draw::<E>()
        .map_err(|_| VerifierError::RandomCoinError)?;

    // 3 ----- OOD consistency check --------------------------------------------------------------
    // make sure that evaluations obtained by evaluating constraints over the out-of-domain frame
    // are consistent with the evaluations of composition polynomial columns sent by the prover

    // read the out-of-domain trace frames (the main trace frame and auxiliary trace frame, if
    // provided) sent by the prover and evaluate constraints over them; also, reseed the public
    // coin with the OOD frames received from the prover.
    let ood_trace_frame = channel.read_ood_trace_frame();
    let ood_main_trace_frame = ood_trace_frame.main_frame();
    let ood_aux_trace_frame = ood_trace_frame.aux_frame();
    let ood_constraint_evaluation_1 = evaluate_constraints(
        &air,
        constraint_coeffs,
        &ood_main_trace_frame,
        &ood_aux_trace_frame,
        aux_trace_rand_elements,
        z,
    );
    public_coin.reseed(H::hash_elements(ood_trace_frame.values()));

    // read evaluations of composition polynomial columns sent by the prover, and reduce them into
    // a single value by computing \sum_{i=0}^{m-1}(z^(i * l) * value_i), where value_i is the
    // evaluation of the ith column polynomial H_i(X) at z, l is the trace length and m is
    // the number of composition column polynomials. This computes H(z) (i.e.
    // the evaluation of the composition polynomial at z) using the fact that
    // H(X) = \sum_{i=0}^{m-1} X^{i * l} H_i(X).
    // Also, reseed the public coin with the OOD constraint evaluations received from the prover.
    let ood_constraint_evaluations = channel.read_ood_constraint_evaluations();
    let ood_constraint_evaluation_2 =
        ood_constraint_evaluations
            .iter()
            .enumerate()
            .fold(E::ZERO, |result, (i, &value)| {
                result + z.exp_vartime(((i * (air.trace_length())) as u32).into()) * value
            });
    public_coin.reseed(H::hash_elements(&ood_constraint_evaluations));

    // finally, make sure the values are the same
    if ood_constraint_evaluation_1 != ood_constraint_evaluation_2 {
        return Err(VerifierError::InconsistentOodConstraintEvaluations);
    }

    // 4 ----- FRI commitments --------------------------------------------------------------------
    // draw coefficients for computing DEEP composition polynomial from the public coin; in the
    // interactive version of the protocol, the verifier sends these coefficients to the prover
    // and the prover uses them to compute the DEEP composition polynomial. the prover, then
    // applies FRI protocol to the evaluations of the DEEP composition polynomial.
    let deep_coefficients = air
        .get_deep_composition_coefficients::<E, R>(&mut public_coin)
        .map_err(|_| VerifierError::RandomCoinError)?;

    // instantiates a FRI verifier with the FRI layer commitments read from the channel. From the
    // verifier's perspective, this is equivalent to executing the commit phase of the FRI protocol.
    // The verifier uses these commitments to update the public coin and draw random points alpha
    // from them; in the interactive version of the protocol, the verifier sends these alphas to
    // the prover, and the prover uses them to compute and commit to the subsequent FRI layers.
    let fri_verifier = FriVerifier::new(
        &mut channel,
        &mut public_coin,
        air.options().to_fri_options(),
        air.trace_poly_degree(),
    )
    .map_err(VerifierError::FriVerificationFailed)?;
    // TODO: make sure air.lde_domain_size() == fri_verifier.domain_size()

    // 5 ----- trace and constraint queries -------------------------------------------------------
    // read proof-of-work nonce sent by the prover and update the public coin with it
    let pow_nonce = channel.read_pow_nonce();
    public_coin.reseed_with_int(pow_nonce);

    // make sure the proof-of-work specified by the grinding factor is satisfied
    if public_coin.leading_zeros() < air.options().grinding_factor() {
        return Err(VerifierError::QuerySeedProofOfWorkVerificationFailed);
    }

    // draw pseudo-random query positions for the LDE domain from the public coin; in the
    // interactive version of the protocol, the verifier sends these query positions to the prover,
    // and the prover responds with decommitments against these positions for trace and constraint
    // composition polynomial evaluations.
    let query_positions = public_coin
        .draw_integers(air.options().num_queries(), air.lde_domain_size())
        .map_err(|_| VerifierError::RandomCoinError)?;

    // read evaluations of trace and constraint composition polynomials at the queried positions;
    // this also checks that the read values are valid against trace and constraint commitments
    let (queried_main_trace_states, queried_aux_trace_states) =
        channel.read_queried_trace_states(&query_positions)?;
    let queried_constraint_evaluations = channel.read_constraint_evaluations(&query_positions)?;

    // 6 ----- DEEP composition -------------------------------------------------------------------
    // compute evaluations of the DEEP composition polynomial at the queried positions
    let composer = DeepComposer::new(&air, &query_positions, z, deep_coefficients);
    let t_composition = composer.compose_trace_columns(
        queried_main_trace_states,
        queried_aux_trace_states,
        ood_main_trace_frame,
        ood_aux_trace_frame,
    );
    let c_composition = composer
        .compose_constraint_evaluations(queried_constraint_evaluations, ood_constraint_evaluations);
    let deep_evaluations = composer.combine_compositions(t_composition, c_composition);

    // 7 ----- Verify low-degree proof -------------------------------------------------------------
    // make sure that evaluations of the DEEP composition polynomial we computed in the previous
    // step are in fact evaluations of a polynomial of degree equal to trace polynomial degree
    fri_verifier
        .verify(&mut channel, &deep_evaluations, &query_positions)
        .map_err(VerifierError::FriVerificationFailed)
}


// Copyright (c) Facebook, Inc. and its affiliates.
//
// This source code is licensed under the MIT license found in the
// LICENSE file in the root directory of this source tree.

//! This crate contains Winterfell STARK prover and verifier.
//!
//! A STARK is a novel proof-of-computation scheme to create efficiently verifiable proofs of the
//! correct execution of a computation. The scheme was developed by Eli Ben-Sasson, Michael Riabzev
//! et al. at Technion - Israel Institute of Technology. STARKs do not require an initial trusted
//! setup, and rely on very few cryptographic assumptions. See [references](#references) for more
//! info.
//!
//! ## Proof generation
//! To generate a proof that a computation was executed correctly, you'll need to do the
//! following:
//!
//! 1. Define an *algebraic intermediate representation* (AIR) for your computation. This can
//!    be done by implementing [Air] trait.
//! 2. Define an execution trace for your computation. This can be done by implementing [Trace]
//!    trait. Alternatively, you can use [TraceTable] struct which already implements [Trace]
//!    trait in cases when this generic implementation works for your use case.
//! 3. Execute your computation and record its execution trace.
//! 4. Define your prover by implementing [Prover] trait. Then execute [Prover::prove()] function
//!    passing the trace generated in the previous step into it as a parameter. The function will
//!    return a instance of [StarkProof].
//!
//! This `StarkProof` can be serialized and sent to a STARK verifier for verification. The size
//! of proof depends on the specifics of a given computation, but for most computations it should
//! be in the range between 15 KB (for very small computations) and 300 KB (for very large
//! computations).
//!
//! Proof generation time is also highly dependent on the specifics of a given computation, but
//! also depends on the capabilities of the machine used to generate the proofs (i.e. on number
//! of CPU cores and memory bandwidth).
//!
//! When the crate is compiled with `concurrent` feature enabled, proof generation will be
//! performed in multiple threads (usually, as many threads as there are logical cores on the
//! machine). The number of threads can be configured via `RAYON_NUM_THREADS` environment
//! variable.
//!
//! ## Prof verification
//! To verify a [StarkProof] generated as described in the previous sections, you'll need to
//! do the following:
//!
//! 1. Define an *algebraic intermediate representation* (AIR) for you computation. This AIR
//!    must be the same as the one used during proof generation process.
//! 2. Execute [verify()] function and supply the AIR of your computation together with the
//!    [StarkProof] and related public inputs as parameters.
//!
//! Proof verification is extremely fast and is nearly independent of the complexity of the
//! computation being verified. In vast majority of cases proofs can be verified in 3 - 5 ms
//! on a modern mid-range laptop CPU (using a single core).
//!
//! There is one exception, however: if a computation requires a lot of `sequence` assertions
//! (see [Assertion] for more info), the verification time will grow linearly in the number of
//! asserted values. But for the impact to be noticeable, the number of asserted values would
//! need to be in tens of thousands. And even for hundreds of thousands of asserted values, the
//! verification time should not exceed 50 ms.
//!
//! # Examples
//! The best way to understand the STARK proof generation and verification process is to go
//! through a trivial example from start to finish. First, we'll need to pick a computation for
//! which we'll be generating and verifying STARK proofs. To keep things simple, we'll use the
//! following:
//!
//! ```no_run
//! use winterfell::math::{fields::f128::BaseElement, FieldElement};
//!
//! fn do_work(start: BaseElement, n: usize) -> BaseElement {
//!    let mut result = start;
//!    for _ in 1..n {
//!        result = result.exp(3) + BaseElement::new(42);
//!    }
//!    result
//! }
//! ```
//!
//! This computation starts with an element in a finite field and then, for the specified number
//! of steps, cubes the element and adds value `42` to it.
//!
//! Suppose, we run this computation for a million steps and get some result. Using STARKs we can
//! prove that we did the work correctly without requiring any verifying party to re-execute the
//! computation. Here is how to do it:
//!
//! First, we need to define an *execution trace* for our computation. This trace should capture
//! the state of the computation at every step of its execution. In our case, the trace is just a
//! single column of intermediate values after each execution of the loop. For example, if we start
//! with value `3` and run the computation for 1,048,576 (same as 220) steps, the
//! execution trace will look like this:
//!
//! | Step      | State  |
//! | :-------: | :----- |
//! | 0         | 3      |
//! | 1         | 69     |
//! | 2         | 328551 |
//! | 3         | 35465687262668193 |
//! | 4         | 237280320818395402166933071684267763523 |
//! | ...       |
//! | 1,048,575 | 247770943907079986105389697876176586605 |
//!
//! To record the trace, we'll use the [TraceTable] struct. The function below, is just a
//! modified version of the `do_work()` function which records every intermediate state of the
//! computation in the [TraceTable] struct:
//!
//! ```no_run
//! use winterfell::{
//!     math::{fields::f128::BaseElement, FieldElement},
//!     TraceTable,
//! };
//!
//! pub fn build_do_work_trace(start: BaseElement, n: usize) -> TraceTable<BaseElement> {
//!     // Instantiate the trace with a given width and length; this will allocate all
//!     // required memory for the trace
//!     let trace_width = 1;
//!     let mut trace = TraceTable::new(trace_width, n);
//!
//!     // Fill the trace with data; the first closure initializes the first state of the
//!     // computation; the second closure computes the next state of the computation based
//!     // on its current state.
//!     trace.fill(
//!         |state| {
//!             state[0] = start;
//!         },
//!         |_, state| {
//!             state[0] = state[0].exp(3u32.into()) + BaseElement::new(42);
//!         },
//!     );
//!
//!     trace
//! }
//! ```
//!
//! Next, we need to define *algebraic intermediate representation* (AIR) for our computation.
//! This process is usually called *arithmetization*. We do this by implementing the [Air] trait.
//! At the high level, the code below does three things:
//!
//! 1. Defines what the public inputs for our computation should look like. These inputs are
//!    called "public" because they must be known to both, the prover and the verifier.
//! 2. Defines a transition function with a single transition constraint. This transition
//!    constraint must evaluate to zero for all valid state transitions, and to non-zero for any
//!    invalid state transition. The degree of this constraint is 3 (see more about constraint
//!    degrees "Constraint degrees" section of [Air] trait documentation).
//! 3. Define two assertions against an execution trace of our computation. These assertions tie
//!    a specific set of public inputs to a specific execution trace (see more about assertions
//!    "Trace assertions" section of [Air] trait documentation).
//!
//! Here is the actual code:
//!
//! ```no_run
//! use winterfell::{
//!     math::{fields::f128::BaseElement, FieldElement, ToElements},
//!     Air, AirContext, Assertion, ByteWriter, EvaluationFrame, ProofOptions, TraceInfo,
//!     TransitionConstraintDegree, crypto::{hashers::Blake3_256, DefaultRandomCoin},
//! };
//!
//! // Public inputs for our computation will consist of the starting value and the end result.
//! pub struct PublicInputs {
//!     start: BaseElement,
//!     result: BaseElement,
//! }
//!
//! // We need to describe how public inputs can be converted to field elements.
//! impl ToElements<BaseElement> for PublicInputs {
//!     fn to_elements(&self) -> Vec<BaseElement> {
//!         vec![self.start, self.result]
//!     }
//! }
//!
//! // For a specific instance of our computation, we'll keep track of the public inputs and
//! // the computation's context which we'll build in the constructor. The context is used
//! // internally by the Winterfell prover/verifier when interpreting this AIR.
//! pub struct WorkAir {
//!     context: AirContext<BaseElement>,
//!     start: BaseElement,
//!     result: BaseElement,
//! }
//!
//! impl Air for WorkAir {
//!     // First, we'll specify which finite field to use for our computation, and also how
//!     // the public inputs must look like.
//!     type BaseField = BaseElement;
//!     type PublicInputs = PublicInputs;
//!
//!     // Here, we'll construct a new instance of our computation which is defined by 3
//!     // parameters: starting value, number of steps, and the end result. Another way to
//!     // think about it is that an instance of our computation is a specific invocation of
//!     // the do_work() function.
//!     fn new(trace_info: TraceInfo, pub_inputs: PublicInputs, options: ProofOptions) -> Self {
//!         // our execution trace should have only one column.
//!         assert_eq!(1, trace_info.width());
//!
//!         // Our computation requires a single transition constraint. The constraint itself
//!         // is defined in the evaluate_transition() method below, but here we need to specify
//!         // the expected degree of the constraint. If the expected and actual degrees of the
//!         // constraints don't match, an error will be thrown in the debug mode, but in release
//!         // mode, an invalid proof will be generated which will not be accepted by any verifier.
//!         let degrees = vec![TransitionConstraintDegree::new(3)];
//!
//!         // We also need to specify the exact number of assertions we will place against the
//!         // execution trace. This number must be the same as the number of items in a vector
//!         // returned from the get_assertions() method below.
//!         let num_assertions = 2;
//!
//!         WorkAir {
//!             context: AirContext::new(trace_info, degrees, num_assertions, options),
//!             start: pub_inputs.start,
//!             result: pub_inputs.result,
//!         }
//!     }
//!
//!     // In this method we'll define our transition constraints; a computation is considered to
//!     // be valid, if for all valid state transitions, transition constraints evaluate to all
//!     // zeros, and for any invalid transition, at least one constraint evaluates to a non-zero
//!     // value. The `frame` parameter will contain current and next states of the computation.
//!     fn evaluate_transition<E: FieldElement + From<Self::BaseField>>(
//!         &self,
//!         frame: &EvaluationFrame<E>,
//!         _periodic_values: &[E],
//!         result: &mut [E],
//!     ) {
//!         // First, we'll read the current state, and use it to compute the expected next state
//!         let current_state = &frame.current()[0];
//!         let next_state = current_state.exp(3u32.into()) + E::from(42u32);
//!
//!         // Then, we'll subtract the expected next state from the actual next state; this will
//!         // evaluate to zero if and only if the expected and actual states are the same.
//!         result[0] = frame.next()[0] - next_state;
//!     }
//!
//!     // Here, we'll define a set of assertions about the execution trace which must be
//!     // satisfied for the computation to be valid. Essentially, this ties computation's
//!     // execution trace to the public inputs.
//!     fn get_assertions(&self) -> Vec<Assertion<Self::BaseField>> {
//!         // for our computation to be valid, value in column 0 at step 0 must be equal to the
//!         // starting value, and at the last step it must be equal to the result.
//!         let last_step = self.trace_length() - 1;
//!         vec![
//!             Assertion::single(0, 0, self.start),
//!             Assertion::single(0, last_step, self.result),
//!         ]
//!     }
//!
//!     // This is just boilerplate which is used by the Winterfell prover/verifier to retrieve
//!     // the context of the computation.
//!     fn context(&self) -> &AirContext<Self::BaseField> {
//!         &self.context
//!     }
//! }
//! ```
//!
//! Next, we need define our prover. This can be done by implementing [Prover] trait. The trait is
//! pretty simple and has just a few required methods. Here is how our implementation could look
//! like:
//!
//! ```no_run
//! use winterfell::{
//!     math::{fields::f128::BaseElement, FieldElement, ToElements},
//!     ProofOptions, Prover, Trace, TraceTable, crypto::{hashers::Blake3_256, DefaultRandomCoin}
//! };
//!
//! # use winterfell::{
//! #   Air, AirContext, Assertion, ByteWriter, EvaluationFrame, TraceInfo,
//! #   TransitionConstraintDegree,
//! # };
//! #
//! # pub struct PublicInputs {
//! #     start: BaseElement,
//! #     result: BaseElement,
//! # }
//! #
//! # impl ToElements<BaseElement> for PublicInputs {
//! #     fn to_elements(&self) -> Vec<BaseElement> {
//! #         vec![self.start, self.result]
//! #     }
//! # }
//! #
//! # pub struct WorkAir {
//! #     context: AirContext<BaseElement>,
//! #     start: BaseElement,
//! #     result: BaseElement,
//! # }
//! #
//! # impl Air for WorkAir {
//! #     type BaseField = BaseElement;
//! #     type PublicInputs = PublicInputs;
//! #
//! #     fn new(trace_info: TraceInfo, pub_inputs: PublicInputs, options: ProofOptions) -> Self {
//! #         assert_eq!(1, trace_info.width());
//! #         let degrees = vec![TransitionConstraintDegree::new(3)];
//! #         WorkAir {
//! #             context: AirContext::new(trace_info, degrees, 2, options),
//! #             start: pub_inputs.start,
//! #             result: pub_inputs.result,
//! #         }
//! #     }
//! #
//! #     fn evaluate_transition<E: FieldElement + From<Self::BaseField>>(
//! #         &self,
//! #         frame: &EvaluationFrame<E>,
//! #         _periodic_values: &[E],
//! #         result: &mut [E],
//! #     ) {
//! #         let current_state = &frame.current()[0];
//! #         let next_state = current_state.exp(3u32.into()) + E::from(42u32);
//! #         result[0] = frame.next()[0] - next_state;
//! #     }
//! #
//! #     fn get_assertions(&self) -> Vec<Assertion<Self::BaseField>> {
//! #         let last_step = self.trace_length() - 1;
//! #         vec![
//! #             Assertion::single(0, 0, self.start),
//! #             Assertion::single(0, last_step, self.result),
//! #         ]
//! #     }
//! #
//! #     fn context(&self) -> &AirContext<Self::BaseField> {
//! #         &self.context
//! #     }
//! # }
//! #
//! // Our prover needs to hold STARK protocol parameters which are specified via ProofOptions
//! // struct.
//! struct WorkProver {
//!     options: ProofOptions
//! }
//!
//! impl WorkProver {
//!     pub fn new(options: ProofOptions) -> Self {
//!         Self { options }
//!     }
//! }
//!
//! // When implementing Prover trait we set the `Air` associated type to the AIR of the
//! // computation we defined previously, and set the `Trace` associated type to `TraceTable`
//! // struct as we don't need to define a custom trace for our computation.
//! impl Prover for WorkProver {
//!     type BaseField = BaseElement;
//!     type Air = WorkAir;
//!     type Trace = TraceTable<Self::BaseField>;
//!     type HashFn = Blake3_256<Self::BaseField>;
//!     type RandomCoin = DefaultRandomCoin<Self::HashFn>;
//!
//!     // Our public inputs consist of the first and last value in the execution trace.
//!     fn get_pub_inputs(&self, trace: &Self::Trace) -> PublicInputs {
//!         let last_step = trace.length() - 1;
//!         PublicInputs {
//!             start: trace.get(0, 0),
//!             result: trace.get(0, last_step),
//!         }
//!     }
//!
//!     fn options(&self) -> &ProofOptions {
//!         &self.options
//!     }
//! }
//! ```
//!
//! Now, we are finally ready to generate and verify STARK proofs.
//!
//! In the code below, we will execute our computation and get the result together with the proof
//! that the computation was executed correctly. Then, we will use this proof (together with the
//! public inputs) to verify that we did in fact execute the computation and got the claimed
//! result.
//!
//! ```
//! # use winterfell::{
//! #    math::{fields::f128::BaseElement, FieldElement, ToElements},
//! #    Air, AirContext, Assertion, ByteWriter, EvaluationFrame, TraceInfo,
//! #    TransitionConstraintDegree, TraceTable, FieldExtension, Prover, ProofOptions,
//! #    StarkProof, Trace, crypto::{hashers::Blake3_256, DefaultRandomCoin},
//! # };
//! #
//! # pub fn build_do_work_trace(start: BaseElement, n: usize) -> TraceTable<BaseElement> {
//! #     let trace_width = 1;
//! #     let mut trace = TraceTable::new(trace_width, n);
//! #     trace.fill(
//! #         |state| {
//! #             state[0] = start;
//! #         },
//! #         |_, state| {
//! #             state[0] = state[0].exp(3u32.into()) + BaseElement::new(42);
//! #         },
//! #     );
//! #     trace
//! # }
//! #
//! #
//! # pub struct PublicInputs {
//! #     start: BaseElement,
//! #     result: BaseElement,
//! # }
//! #
//! # impl ToElements<BaseElement> for PublicInputs {
//! #     fn to_elements(&self) -> Vec<BaseElement> {
//! #         vec![self.start, self.result]
//! #     }
//! # }
//! #
//! # pub struct WorkAir {
//! #     context: AirContext<BaseElement>,
//! #     start: BaseElement,
//! #     result: BaseElement,
//! # }
//! #
//! # impl Air for WorkAir {
//! #     type BaseField = BaseElement;
//! #     type PublicInputs = PublicInputs;
//! #
//! #     fn new(trace_info: TraceInfo, pub_inputs: PublicInputs, options: ProofOptions) -> Self {
//! #         assert_eq!(1, trace_info.width());
//! #         let degrees = vec![TransitionConstraintDegree::new(3)];
//! #         WorkAir {
//! #             context: AirContext::new(trace_info, degrees, 2, options),
//! #             start: pub_inputs.start,
//! #             result: pub_inputs.result,
//! #         }
//! #     }
//! #
//! #     fn evaluate_transition<E: FieldElement + From<Self::BaseField>>(
//! #         &self,
//! #         frame: &EvaluationFrame<E>,
//! #         _periodic_values: &[E],
//! #         result: &mut [E],
//! #     ) {
//! #         let current_state = &frame.current()[0];
//! #         let next_state = current_state.exp(3u32.into()) + E::from(42u32);
//! #         result[0] = frame.next()[0] - next_state;
//! #     }
//! #
//! #     fn get_assertions(&self) -> Vec<Assertion<Self::BaseField>> {
//! #         let last_step = self.trace_length() - 1;
//! #         vec![
//! #             Assertion::single(0, 0, self.start),
//! #             Assertion::single(0, last_step, self.result),
//! #         ]
//! #     }
//! #
//! #     fn context(&self) -> &AirContext<Self::BaseField> {
//! #         &self.context
//! #     }
//! # }
//! #
//! # struct WorkProver {
//! #    options: ProofOptions
//! # }
//! #
//! # impl WorkProver {
//! #    pub fn new(options: ProofOptions) -> Self {
//! #        Self { options }
//! #    }
//! # }
//! #
//! # impl Prover for WorkProver {
//! #    type BaseField = BaseElement;
//! #    type Air = WorkAir;
//! #    type Trace = TraceTable<Self::BaseField>;
//! #    type HashFn = Blake3_256<Self::BaseField>;
//! #    type RandomCoin = DefaultRandomCoin<Self::HashFn>;
//! #
//! #    fn get_pub_inputs(&self, trace: &Self::Trace) -> PublicInputs {
//! #        let last_step = trace.length() - 1;
//! #        PublicInputs {
//! #            start: trace.get(0, 0),
//! #            result: trace.get(0, last_step),
//! #        }
//! #    }
//! #
//! #    fn options(&self) -> &ProofOptions {
//! #        &self.options
//! #    }
//! #  }
//! #
//! // We'll just hard-code the parameters here for this example. We'll also just run the
//! // computation just for 1024 steps to save time during testing.
//! let start = BaseElement::new(3);
//! let n = 1024;
//!
//! // Build the execution trace and get the result from the last step.
//! let trace = build_do_work_trace(start, n);
//! let result = trace.get(0, n - 1);
//!
//! // Define proof options; these will be enough for ~96-bit security level.
//! let options = ProofOptions::new(
//!     32, // number of queries
//!     8,  // blowup factor
//!     0,  // grinding factor
//!     FieldExtension::None,
//!     8,  // FRI folding factor
//!     31, // FRI max remainder polynomial degree
//! );
//!
//! // Instantiate the prover and generate the proof.
//! let prover = WorkProver::new(options);
//! let proof = prover.prove(trace).unwrap();
//!
//! // Verify the proof. The number of steps and options are encoded in the proof itself,
//! // so we don't need to pass them explicitly to the verifier.
//! let pub_inputs = PublicInputs { start, result };
//! assert!(winterfell::verify::<WorkAir,
//!                              Blake3_256<BaseElement>,
//!                              DefaultRandomCoin<Blake3_256<BaseElement>>
//!                             >(proof, pub_inputs).is_ok());
//! ```
//!
//! That's all there is to it!
//!
//! # References
//!
//! If you are interested in learning how STARKs work under the hood, here are a few links to get
//! you started. From the standpoint of this library, *arithmetization* is by far the most
//! important concept to understand.
//!
//! * STARKs whitepaper: [Scalable, transparent, and post-quantum secure computational integrity](https://eprint.iacr.org/2018/046)
//! * STARKs vs. SNARKs: [A Cambrian Explosion of Crypto Proofs](https://nakamoto.com/cambrian-explosion-of-crypto-proofs/)
//!
//! Vitalik Buterin's blog series on zk-STARKs:
//! * [STARKs, part 1: Proofs with Polynomials](https://vitalik.ca/general/2017/11/09/starks_part_1.html)
//! * [STARKs, part 2: Thank Goodness it's FRI-day](https://vitalik.ca/general/2017/11/22/starks_part_2.html)
//! * [STARKs, part 3: Into the Weeds](https://vitalik.ca/general/2018/07/21/starks_part_3.html)
//!
//! StarkWare's STARK Math blog series:
//! * [STARK Math: The Journey Begins](https://medium.com/starkware/stark-math-the-journey-begins-51bd2b063c71)
//! * [Arithmetization I](https://medium.com/starkware/arithmetization-i-15c046390862)
//! * [Arithmetization II](https://medium.com/starkware/arithmetization-ii-403c3b3f4355)
//! * [Low Degree Testing](https://medium.com/starkware/low-degree-testing-f7614f5172db)
//! * [A Framework for Efficient STARKs](https://medium.com/starkware/a-framework-for-efficient-starks-19608ba06fbe)

#![cfg_attr(not(feature = "std"), no_std)]

pub use prover::{
    crypto, iterators, math, Air, AirContext, Assertion, AuxTraceRandElements, BoundaryConstraint,
    BoundaryConstraintGroup, ByteReader, ByteWriter, ColMatrix, ConstraintCompositionCoefficients,
    ConstraintDivisor, DeepCompositionCoefficients, Deserializable, DeserializationError,
    EvaluationFrame, FieldExtension, ProofOptions, Prover, ProverError, Serializable, SliceReader,
    StarkProof, Trace, TraceInfo, TraceLayout, TraceTable, TraceTableFragment,
    TransitionConstraintDegree,
};
pub use verifier::{verify, VerifierError};


use wasm_bindgen::prelude::*;

// Example format to write functions:
#[wasm_bindgen(js_name = camelCaseName)] // js_name must equal function name tested on client
pub fn snake_case_name(num: i32) -> i32 { // Function must be public
    // All numbers in JS are 32-bit
    num
}

// First function written for you - you still need to add the logic :)
#[wasm_bindgen(js_name = multiplesOf3and5)]
pub fn multiples_of_3_and_5(n: i32) -> i32 {
    n
}


extern crate message;
use message::process_instruction;
use borsh::BorshDeserialize;

use solana_program::{account_info::AccountInfo, program_error::ProgramError, pubkey::Pubkey};

#[derive(BorshDeserialize, Debug)]
pub struct MessageStructForTest {
    pub message: String
}

#[test]
fn owner_not_program_id() {
    let program_id = Pubkey::new_unique();
    let owner = Pubkey::new_unique();
    let mut data = vec![0; 284];
    let mut lam = 2;
    let account_info = AccountInfo::new(
        &program_id,
        false,
        true,
        &mut lam,
        &mut data,
        &owner,
        false,
        2,
    );
    let accounts = vec![account_info];
    let instruction_data = vec![];
    let result = process_instruction(&program_id, &accounts, &instruction_data);
    assert_eq!(result, Err(ProgramError::IncorrectProgramId));
}

#[test]
fn instruction_is_deserialized() {
    let program_id = Pubkey::new_unique();
    let mut data = vec![0; 284];
    let mut lam = 2;
    let account_info = AccountInfo::new(
        &program_id,
        false,
        true,
        &mut lam,
        &mut data,
        &program_id,
        false,
        2,
    );
    let accounts = vec![account_info];
    let instruction_data = "Hello World!".as_bytes();
    let _result = process_instruction(&program_id, &accounts, &instruction_data);
    let data = MessageStructForTest::try_from_slice(String::from_utf8(accounts[0].data.borrow().to_vec()).unwrap().as_bytes()).unwrap();
    let fmt = format!("{: <280}", "Hello World!");
    assert_eq!(fmt, data.message);
}

#[test]
fn instruction_not_string() {
    let program_id = Pubkey::new_unique();
    let mut data = vec![0; 284];
    let mut lam = 2;
    let account_info = AccountInfo::new(
        &program_id,
        false,
        true,
        &mut lam,
        &mut data,
        &program_id,
        false,
        2,
    );
    let accounts = vec![account_info];
    let instruction_data = vec![0, 159, 146, 150];
    let result = process_instruction(&program_id, &accounts, &instruction_data);
    assert_eq!(result, Err(ProgramError::InvalidInstructionData));
}

#[test]
fn instruction_too_long() {
    let program_id = Pubkey::new_unique();
    let mut data = vec![0; 284];
    let mut lam = 2;
    let account_info = AccountInfo::new(
        &program_id,
        false,
        true,
        &mut lam,
        &mut data,
        &program_id,
        false,
        2,
    );
    let accounts = vec![account_info];
    let instruction_data = vec![0; 281];
    let result = process_instruction(&program_id, &accounts, &instruction_data);
    assert_eq!(result, Err(ProgramError::InvalidInstructionData));
}

#[test]
fn no_accounts() {
    let program_id = Pubkey::new_unique();
    let accounts = vec![];
    let instruction_data = vec![];
    let result = process_instruction(&program_id, &accounts, &instruction_data);
    assert_eq!(result, Err(ProgramError::NotEnoughAccountKeys));
}

#[test]
fn instruction_data_padded() {
    let program_id = Pubkey::new_unique();
    let mut data = vec![0; 284];
    let mut lam = 2;
    let account_info = AccountInfo::new(
        &program_id,
        false,
        true,
        &mut lam,
        &mut data,
        &program_id,
        false,
        2,
    );
    let accounts = vec![account_info];
    let instruction_data = "Hello World!".as_bytes();
    let _result = process_instruction(&program_id, &accounts, &instruction_data);
    let account_data = accounts[0].data.borrow();
    assert_eq!(account_data.len(), 284);
}

#[test]
fn success() {
    let program_id = Pubkey::new_unique();
    let mut data = vec![0; 284];
    let mut lam = 2;
    let account_info = AccountInfo::new(
        &program_id,
        false,
        true,
        &mut lam,
        &mut data,
        &program_id,
        false,
        2,
    );
    let accounts = vec![account_info];
    let instruction_data = "Hello World!".as_bytes();
    let result = process_instruction(&program_id, &accounts, &instruction_data);
    assert_eq!(result, Ok(()));
}


use anchor_lang::prelude::*;

declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS");

#[program]
pub mod rock_destroyer {
    use super::*;

    pub fn initialize(ctx: Context<Initialize>) -> Result<()> {
        Ok(())
    }
}

#[derive(Accounts)]
pub struct Initialize {}


use anchor_lang::prelude::*;
use num_derive;
use num_traits::FromPrimitive;

declare_id!("BUfb6FXLkiSpMnJnMR4Q5uGZYZkaNGytjhLwiiJQsE8F");

#[program]
pub mod tic_tac_toe {
    use super::*;

    pub fn setup_game(
        ctx: Context<SetupGame>,
        player_two_pubkey: Pubkey,
        _game_id: String,
    ) -> Result<()> {
        let player_one = &ctx.accounts.player_one;
        let player_one_pubkey = player_one.key();

        let game = &mut ctx.accounts.game;

        game.start([player_one_pubkey, player_two_pubkey])
    }

    pub fn play(ctx: Context<Play>, tile: Tile) -> Result<()> {
        let game = &mut ctx.accounts.game;

        require_keys_eq!(
            game.current_player(),
            ctx.accounts.player.key(),
            TicTacToeError::NotPlayersTurn
        );

        game.play(&tile)
    }
}

#[derive(Accounts)]
#[instruction(player_two_pubkey: Pubkey, _game_id: String)]
pub struct SetupGame<'info> {
    #[account(
        init,
        payer = player_one,
        space = 8 + Game::MAXIMUM_SIZE,
        seeds = [b"game", player_one.key().as_ref(), _game_id.as_bytes()],
        bump
    )]
    pub game: Account<'info, Game>,
    #[account(mut)]
    pub player_one: Signer<'info>,
    pub system_program: Program<'info, System>,
}

#[account]
pub struct Game {
    players: [Pubkey; 2],          // (32 * 2)
    turn: u8,                      // 1
    board: [[Option<Sign>; 3]; 3], // 9 * (1 + 1) = 18
    state: GameState,              // 32 + 1
}

#[derive(Accounts)]
pub struct Play<'info> {
    #[account(mut)]
    pub game: Account<'info, Game>,
    pub player: Signer<'info>,
}

#[derive(AnchorSerialize, AnchorDeserialize, Clone, PartialEq)]
pub enum GameState {
    Active,
    Tie,
    Won { winner: Pubkey },
}

#[derive(AnchorSerialize, AnchorDeserialize, num_derive::FromPrimitive, Copy, Clone, PartialEq)]
pub enum Sign {
    X,
    O,
}

impl Game {
    pub const MAXIMUM_SIZE: usize = (32 * 2) + 1 + (9 * (1 + 1)) + (32 + 1);

    pub fn start(&mut self, players: [Pubkey; 2]) -> Result<()> {
        require_eq!(self.turn, 0, TicTacToeError::GameAlreadyStarted);
        self.players = players;
        self.turn = 1;
        Ok(())
    }

    pub fn is_active(&self) -> bool {
        self.state == GameState::Active
    }

    fn current_player_index(&self) -> usize {
        ((self.turn - 1) % 2) as usize
    }

    pub fn current_player(&self) -> Pubkey {
        self.players[self.current_player_index()]
    }

    pub fn play(&mut self, tile: &Tile) -> Result<()> {
        require!(self.is_active(), TicTacToeError::GameAlreadyOver);

        match tile {
            tile @ Tile {
                row: 0..=2,
                column: 0..=2,
            } => match self.board[tile.row as usize][tile.column as usize] {
                Some(_) => return Err(TicTacToeError::TileAlreadySet.into()),
                None => {
                    self.board[tile.row as usize][tile.column as usize] =
                        Some(Sign::from_usize(self.current_player_index()).unwrap());
                }
            },
            _ => return Err(TicTacToeError::TileOutOfBounds.into()),
        }

        self.update_state();

        if GameState::Active == self.state {
            self.turn += 1;
        }

        Ok(())
    }

    fn is_winning_trio(&self, trio: [(usize, usize); 3]) -> bool {
        let [first, second, third] = trio;
        self.board[first.0][first.1].is_some()
            && self.board[first.0][first.1] == self.board[second.0][second.1]
            && self.board[first.0][first.1] == self.board[third.0][third.1]
    }

    fn update_state(&mut self) {
        for i in 0..=2 {
            // three of the same in one row
            if self.is_winning_trio([(i, 0), (i, 1), (i, 2)]) {
                self.state = GameState::Won {
                    winner: self.current_player(),
                };
                return;
            }
            // three of the same in one column
            if self.is_winning_trio([(0, i), (1, i), (2, i)]) {
                self.state = GameState::Won {
                    winner: self.current_player(),
                };
                return;
            }
        }

        // three of the same in one diagonal
        if self.is_winning_trio([(0, 0), (1, 1), (2, 2)])
            || self.is_winning_trio([(0, 2), (1, 1), (2, 0)])
        {
            self.state = GameState::Won {
                winner: self.current_player(),
            };
            return;
        }

        // reaching this code means the game has not been won,
        // so if there are unfilled tiles left, it's still active
        for row in 0..=2 {
            for column in 0..=2 {
                if self.board[row][column].is_none() {
                    return;
                }
            }
        }

        // game has not been won
        // game has no more free tiles
        // -> game ends in a tie
        self.state = GameState::Tie;
    }
}

#[derive(AnchorSerialize, AnchorDeserialize)]
pub struct Tile {
    row: u8,
    column: u8,
}

#[error_code]
pub enum TicTacToeError {
    TileOutOfBounds,
    TileAlreadySet,
    GameAlreadyOver,
    NotPlayersTurn,
    GameAlreadyStarted,
}


use borsh::{BorshDeserialize, BorshSerialize};
use solana_program::{
    account_info::AccountInfo, entrypoint, entrypoint::ProgramResult, msg,
    program_error::ProgramError, pubkey::Pubkey,
};

entrypoint!(process_instruction);

pub fn process_instruction(
    program_id: &Pubkey,
    accounts: &[AccountInfo],
    _instruction_data: &[u8],
) -> ProgramResult {
    msg!("Hello World");

    let mut accounts_iter = accounts.iter();
    if let Some(account) = accounts_iter.next() {
        if account.owner != program_id {
            msg!("Account info does not match program id");
            return Err(ProgramError::IncorrectProgramId);
        }

        let mut greeting_account = GreetingAccount::try_from_slice(&account.data.borrow())?;

        greeting_account.counter += 1;
        let acc_data = &mut account.data.borrow_mut()[..];
        greeting_account.serialize(&mut acc_data.as_mut())?;

        msg!("Greeted {} time(s)!", greeting_account.counter);

        Ok(())
    } else {
        msg!("No accounts provided to say hello to");
        return Err(ProgramError::NotEnoughAccountKeys);
    }
}

/// Define the type of state stored in accounts
#[derive(BorshSerialize, BorshDeserialize, Debug)]
pub struct GreetingAccount {
    /// number of greetings
    pub counter: u32,
}


// Write your code here:

// Do not edit below this line!
#[cfg(test)]
mod tests {
    use serde::{Serialize, Deserialize};

    #[test]
    fn account_struct_is_defined() {
        use super::Account;
        let _acc: Account;
        assert!(true, "This test should compile to pass");
    }
    #[test]
    fn account_struct_has_total_clicks() {
        use super::Account;
        fn _total_clicks(acc: Account) -> u64 {
            acc.total_clicks
        }
        assert!(true, "This test should compile to pass");
    }
    #[test]
    fn account_struct_has_clickers() {
        use super::Account;
        fn _clickers(acc: Account) -> Vec<String> {
            acc.clickers
        }
        assert!(true, "This test should compile to pass");
    }
    #[test]
    fn account_struct_is_serde() {
        use super::Account;
        fn account_serde<'a, T>(_acc: T)
        where T: Serialize + Deserialize<'a>
        {
            assert!(true, "This test should compile to pass");
        }
        let new_acc = Account {
            total_clicks: 10,
            clickers: vec![String::from("Test")]
        };
        account_serde(new_acc);
    }
    #[test]
    fn context_struct_is_defined() {
        use super::Context;
        let _con: Context;
        assert!(true, "This test should compile to pass");
    }
    #[test]
    fn context_struct_has_base_account() {
        use super::{Account, Context};
        fn _base_account(con: Context) -> Account {
            con.base_account
        }
        assert!(true, "This test should compile to pass");
    }
    #[test]
    fn context_struct_is_serde() {
        use super::{Context, Account};
        fn context_serde<'a, T>(_acc: T)
        where T: Serialize + Deserialize<'a>
        {
            assert!(true, "This test should compile to pass");
        }
        let new_acc = Account {
            total_clicks: 10,
            clickers: vec![String::from("Test")]
        };
        let new_con = Context {
            base_account: new_acc
        };
        context_serde(new_con);
    }
}


extern crate build_a_smart_contract_in_rust;

use build_a_smart_contract_in_rust::{Account, Context};
use wasm_bindgen::JsValue;
use wasm_bindgen_test::*;

wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser);

#[wasm_bindgen_test]
fn is_public() {
    use build_a_smart_contract_in_rust::get_contract_account;
    let _t = get_contract_account;
    assert!(true, "This test should just compile to pass");
}

#[wasm_bindgen_test]
fn returns_result() {
    use build_a_smart_contract_in_rust::get_contract_account;

    let res = get_contract_account(js_con());
    let _v = res.is_ok();
    assert!(true, "This test should just compile to pass");
}

#[wasm_bindgen_test]
fn returns_account() {
    use build_a_smart_contract_in_rust::get_contract_account;

    let res = get_contract_account(js_con());
    match res {
        Ok(v) => {
            let _account: Account = v.into_serde().expect("get_contract_account returns a value serialisable into an Account.");
        },
        Err(_e) => {
            assert!(false, "get_contract should not have returned an Err variant");
        }
    };
}

#[wasm_bindgen_test]
fn returns_updated_account() {
    use build_a_smart_contract_in_rust::get_contract_account;

    let mut context = fix_context();
    context.base_account.clickers.push("ahmad".to_string());
    let res = get_contract_account(JsValue::from_serde(&context).expect("can turn context into JsValue"));
    match res {
        Ok(v) => {
            let _account: Account = v.into_serde().expect("get_contract_account returns a value serialisable into an Account.");
        },
        Err(_e) => {
            assert!(false, "get_contract should not have returned an Err variant");
        }
    };
}

fn fix_context() -> Context {
    let acc = Account {
        total_clicks: 10,
        clickers: vec![String::from("tom"), String::from("shaun")]
    };
    let con = Context {
        base_account: acc
    };
    con
}

fn js_con() -> JsValue {
    JsValue::from_serde(&fix_context()).expect("can turn context into JsValue")
}