arnaucube
arnaucube/miden-cryptoPublic Self-hosted repository
miden-crypto/src/dsa/rpo_stark/stark/prover.rs
src/dsa/rpo_stark/stark/prover.rsRaw
  1use core::marker::PhantomData;
  2
  3use rand_chacha::ChaCha20Rng;
  4use winter_air::{
  5    AuxRandElements, ConstraintCompositionCoefficients, PartitionOptions, ZkParameters,
  6};
  7use winter_crypto::{ElementHasher, SaltedMerkleTree};
  8use winter_math::{fields::f64::BaseElement, FieldElement};
  9use winter_prover::{
 10    matrix::ColMatrix, CompositionPoly, CompositionPolyTrace, DefaultConstraintCommitment,
 11    DefaultConstraintEvaluator, DefaultTraceLde, ProofOptions, Prover, StarkDomain, Trace,
 12    TraceInfo, TracePolyTable, TraceTable,
 13};
 14
 15use super::air::{PublicInputs, RescueAir, HASH_CYCLE_LEN};
 16use crate::{
 17    hash::{rpo::Rpo256, STATE_WIDTH},
 18    rand::RpoRandomCoin,
 19    Word, ZERO,
 20};
 21
 22// PROVER
 23// ================================================================================================
 24
 25/// A prover for the RPO STARK-based signature scheme.
 26///
 27/// The signature is based on the the one-wayness of the RPO hash function but it is generic over
 28/// the hash function used for instantiating the random oracle for the BCS transform.
 29pub(crate) struct RpoSignatureProver<H: ElementHasher + Sync> {
 30    message: Word,
 31    options: ProofOptions,
 32    _hasher: PhantomData<H>,
 33}
 34
 35impl<H: ElementHasher + Sync> RpoSignatureProver<H> {
 36    pub(crate) fn new(message: Word, options: ProofOptions) -> Self {
 37        Self { message, options, _hasher: PhantomData }
 38    }
 39
 40    pub(crate) fn build_trace(&self, sk: Word) -> TraceTable<BaseElement> {
 41        let mut trace = TraceTable::new(STATE_WIDTH, HASH_CYCLE_LEN);
 42
 43        trace.fill(
 44            |state| {
 45                // initialize first half of the rate portion of the state with the secret key
 46                state[0] = ZERO;
 47                state[1] = ZERO;
 48                state[2] = ZERO;
 49                state[3] = ZERO;
 50                state[4] = sk[0];
 51                state[5] = sk[1];
 52                state[6] = sk[2];
 53                state[7] = sk[3];
 54                state[8] = ZERO;
 55                state[9] = ZERO;
 56                state[10] = ZERO;
 57                state[11] = ZERO;
 58            },
 59            |step, state| {
 60                Rpo256::apply_round(
 61                    state.try_into().expect("should not fail given the size of the array"),
 62                    step,
 63                );
 64            },
 65        );
 66        trace
 67    }
 68}
 69
 70impl<H: ElementHasher> Prover for RpoSignatureProver<H>
 71where
 72    H: ElementHasher<BaseField = BaseElement> + Sync,
 73{
 74    type BaseField = BaseElement;
 75    type Air = RescueAir;
 76    type Trace = TraceTable<BaseElement>;
 77    type HashFn = Rpo256;
 78    type VC = SaltedMerkleTree<Self::HashFn, Self::ZkPrng>;
 79    type RandomCoin = RpoRandomCoin;
 80    type TraceLde<E: FieldElement<BaseField = Self::BaseField>> =
 81        DefaultTraceLde<E, Self::HashFn, Self::VC>;
 82    type ConstraintCommitment<E: FieldElement<BaseField = Self::BaseField>> =
 83        DefaultConstraintCommitment<E, Self::HashFn, Self::ZkPrng, Self::VC>;
 84    type ConstraintEvaluator<'a, E: FieldElement<BaseField = Self::BaseField>> =
 85        DefaultConstraintEvaluator<'a, Self::Air, E>;
 86    type ZkPrng = ChaCha20Rng;
 87
 88    fn get_pub_inputs(&self, trace: &Self::Trace) -> PublicInputs {
 89        let last_step = trace.length() - 1;
 90        // Note that the message is not part of the execution trace but is part of the public
 91        // inputs. This is explained in the reference description of the DSA and intuitively
 92        // it is done in order to make sure that the message is part of the Fiat-Shamir
 93        // transcript and hence binds the proof/signature to the message
 94        PublicInputs {
 95            pub_key: [
 96                trace.get(4, last_step),
 97                trace.get(5, last_step),
 98                trace.get(6, last_step),
 99                trace.get(7, last_step),
100            ],
101            msg: self.message,
102        }
103    }
104
105    fn options(&self) -> &ProofOptions {
106        &self.options
107    }
108
109    fn new_trace_lde<E: FieldElement<BaseField = Self::BaseField>>(
110        &self,
111        trace_info: &TraceInfo,
112        main_trace: &ColMatrix<Self::BaseField>,
113        domain: &StarkDomain<Self::BaseField>,
114        partition_option: PartitionOptions,
115        zk_parameters: Option<ZkParameters>,
116        prng: &mut Option<Self::ZkPrng>,
117    ) -> (Self::TraceLde<E>, TracePolyTable<E>) {
118        DefaultTraceLde::new(trace_info, main_trace, domain, partition_option, zk_parameters, prng)
119    }
120
121    fn new_evaluator<'a, E: FieldElement<BaseField = Self::BaseField>>(
122        &self,
123        air: &'a Self::Air,
124        aux_rand_elements: Option<AuxRandElements<E>>,
125        composition_coefficients: ConstraintCompositionCoefficients<E>,
126    ) -> Self::ConstraintEvaluator<'a, E> {
127        DefaultConstraintEvaluator::new(air, aux_rand_elements, composition_coefficients)
128    }
129
130    fn build_constraint_commitment<E: FieldElement<BaseField = Self::BaseField>>(
131        &self,
132        composition_poly_trace: CompositionPolyTrace<E>,
133        num_constraint_composition_columns: usize,
134        domain: &StarkDomain<Self::BaseField>,
135        partition_options: PartitionOptions,
136        zk_parameters: Option<ZkParameters>,
137        prng: &mut Option<Self::ZkPrng>,
138    ) -> (Self::ConstraintCommitment<E>, CompositionPoly<E>) {
139        DefaultConstraintCommitment::new(
140            composition_poly_trace,
141            num_constraint_composition_columns,
142            domain,
143            partition_options,
144            zk_parameters,
145            prng,
146        )
147    }
148}