mina_tree/proofs/
to_field_elements.rs

1use std::borrow::Cow;
2
3use crate::{
4    default_zkapp_hash,
5    proofs::{public_input::plonk_checks::ShiftingValue, util::four_u64_to_field},
6};
7use ark_ff::{Field, One, Zero};
8use kimchi::proof::{PointEvaluations, ProofEvaluations, ProverCommitments, ProverProof};
9use mina_curves::pasta::{Fp, Fq};
10use mina_p2p_messages::{string::ByteString, v2};
11use mina_signer::CompressedPubKey;
12use poly_commitment::evaluation_proof::OpeningProof;
13
14use crate::{
15    proofs::{
16        public_input::prepared_statement::{DeferredValues, Plonk, ProofState},
17        step::OptFlag,
18        util::two_u64_to_field,
19    },
20    scan_state::{
21        currency::{self, Sgn},
22        fee_excess::FeeExcess,
23        pending_coinbase,
24        scan_state::transaction_snark::{Registers, SokDigest, Statement},
25        transaction_logic::{
26            protocol_state::{EpochData, EpochLedger},
27            transaction_union_payload,
28            zkapp_statement::ZkappStatement,
29        },
30    },
31    staged_ledger::hash::StagedLedgerHash,
32    Account, MyCow, ReceiptChainHash, TimingAsRecord, TokenId, TokenSymbol, VotingFor,
33};
34
35use super::{
36    field::{Boolean, CircuitVar, FieldWitness, GroupAffine},
37    step::PerProofWitness,
38    transaction::{
39        field_to_bits, InnerCurve, PlonkVerificationKeyEvals, StepMainProofState, StepMainStatement,
40    },
41    unfinalized::{AllEvals, EvalsWithPublicInput},
42};
43
44pub trait ToFieldElementsDebug: ToFieldElements<Fp> + std::fmt::Debug {}
45
46impl<T: ToFieldElements<Fp> + std::fmt::Debug> ToFieldElementsDebug for T {}
47
48pub trait ToFieldElements<F: Field> {
49    fn to_field_elements(&self, fields: &mut Vec<F>);
50
51    fn to_field_elements_owned(&self) -> Vec<F> {
52        let mut fields = Vec::with_capacity(1024);
53        self.to_field_elements(&mut fields);
54        fields
55    }
56}
57
58impl ToFieldElements<Fp> for ZkappStatement {
59    fn to_field_elements(&self, fields: &mut Vec<Fp>) {
60        fields.extend(self.to_field_elements())
61    }
62}
63
64// impl ToFieldElements for Statement<SokDigest> {
65//     fn to_field_elements(&self) -> Vec<Fp> {
66//         let mut inputs = crate::Inputs::new();
67//         inputs.append(self);
68
69//         inputs.to_fields()
70//     }
71// }
72
73impl<F: Field> ToFieldElements<F> for () {
74    fn to_field_elements(&self, _fields: &mut Vec<F>) {}
75}
76
77impl ToFieldElements<Fp> for SokDigest {
78    fn to_field_elements(&self, fields: &mut Vec<Fp>) {
79        const BITS: [u8; 8] = [1, 2, 4, 8, 16, 32, 64, 128];
80        for byte in &self.0 {
81            fields.extend(BITS.iter().map(|bit| Fp::from((byte & bit != 0) as u64)));
82        }
83    }
84}
85
86/// Unlike expectations, OCaml doesn't call `Sok_digest.to_field_elements` on
87/// `Statement_intf.to_field_elements`, it is probably overwritten somewhere
88/// but I was not able to find which method exactly is used:
89/// I added lots of `printf` everywhere but they are never called/triggered.
90/// I suspect it uses the `to_hlist`, or the `Typ`, or the data spec, but
91/// again, I couldn't confirm.
92///
93/// This implementation relies only on the output I observed here, using
94/// reproducible input test data:
95/// <https://github.com/MinaProtocol/mina/blob/bfd1009abdbee78979ff0343cc73a3480e862f58/src/lib/pickles/composition_types/composition_types.ml#L714C11-L714C48>
96///
97/// TODO: Fuzz this method, compare with OCaml
98impl<T: ToFieldElements<Fp>> ToFieldElements<Fp> for Statement<T> {
99    fn to_field_elements(&self, fields: &mut Vec<Fp>) {
100        let Self {
101            source,
102            target,
103            connecting_ledger_left,
104            connecting_ledger_right,
105            supply_increase,
106            fee_excess,
107            sok_digest,
108        } = self;
109
110        let sign_to_field = |sgn| -> Fp {
111            use crate::scan_state::currency::Sgn::*;
112            match sgn {
113                Pos => 1i64,
114                Neg => -1,
115            }
116            .into()
117        };
118
119        let mut add_register = |registers: &Registers| {
120            let Registers {
121                first_pass_ledger,
122                second_pass_ledger,
123                pending_coinbase_stack,
124                local_state,
125            } = registers;
126
127            first_pass_ledger.to_field_elements(fields);
128            second_pass_ledger.to_field_elements(fields);
129            pending_coinbase_stack.to_field_elements(fields);
130            local_state.stack_frame.to_field_elements(fields);
131            local_state.call_stack.to_field_elements(fields);
132            local_state.transaction_commitment.to_field_elements(fields);
133            local_state
134                .full_transaction_commitment
135                .to_field_elements(fields);
136            local_state.excess.magnitude.to_field_elements(fields);
137            sign_to_field(local_state.excess.sgn).to_field_elements(fields);
138            local_state
139                .supply_increase
140                .magnitude
141                .to_field_elements(fields);
142            sign_to_field(local_state.supply_increase.sgn).to_field_elements(fields);
143            local_state.ledger.to_field_elements(fields);
144            local_state.success.to_field_elements(fields);
145            local_state.account_update_index.to_field_elements(fields);
146            local_state.will_succeed.to_field_elements(fields);
147        };
148
149        add_register(source);
150        add_register(target);
151        connecting_ledger_left.to_field_elements(fields);
152        connecting_ledger_right.to_field_elements(fields);
153        supply_increase.magnitude.to_field_elements(fields);
154        sign_to_field(supply_increase.sgn).to_field_elements(fields);
155
156        let FeeExcess {
157            fee_token_l,
158            fee_excess_l,
159            fee_token_r,
160            fee_excess_r,
161        } = fee_excess;
162
163        fee_token_l.to_field_elements(fields);
164        fee_excess_l.magnitude.to_field_elements(fields);
165        sign_to_field(fee_excess_l.sgn).to_field_elements(fields);
166
167        fee_token_r.to_field_elements(fields);
168        fee_excess_r.magnitude.to_field_elements(fields);
169        sign_to_field(fee_excess_r.sgn).to_field_elements(fields);
170
171        sok_digest.to_field_elements(fields)
172    }
173}
174
175impl<F: FieldWitness, T: ToFieldElements<F>> ToFieldElements<F> for Vec<T> {
176    fn to_field_elements(&self, fields: &mut Vec<F>) {
177        self.iter().for_each(|v| v.to_field_elements(fields));
178    }
179}
180
181impl<F: FieldWitness, T: ToFieldElements<F>> ToFieldElements<F> for Box<[T]> {
182    fn to_field_elements(&self, fields: &mut Vec<F>) {
183        self.iter().for_each(|v| v.to_field_elements(fields));
184    }
185}
186
187impl<F: FieldWitness> ToFieldElements<F> for Fp {
188    fn to_field_elements(&self, fields: &mut Vec<F>) {
189        use crate::proofs::field::IntoGeneric;
190        fields.push(self.into_gen());
191    }
192}
193
194impl<F: FieldWitness, T: ToFieldElements<F> + Clone> ToFieldElements<F> for Cow<'_, T> {
195    fn to_field_elements(&self, fields: &mut Vec<F>) {
196        let this: &T = self.as_ref();
197        this.to_field_elements(fields)
198    }
199}
200
201// pack
202pub fn field_of_bits<F: FieldWitness, const N: usize>(bs: &[bool; N]) -> F {
203    bs.iter().rev().fold(F::zero(), |acc, b| {
204        let acc = acc + acc;
205        if *b {
206            acc + F::one()
207        } else {
208            acc
209        }
210    })
211}
212
213impl<F: FieldWitness> ToFieldElements<F> for Fq {
214    fn to_field_elements(&self, fields: &mut Vec<F>) {
215        use crate::proofs::field::IntoGeneric;
216        use std::any::TypeId;
217
218        // TODO: Refactor when specialization is stable
219        if TypeId::of::<F>() == TypeId::of::<Fq>() {
220            fields.push(self.into_gen());
221        } else {
222            // `Fq` is larger than `Fp` so we have to split the field (low & high bits)
223            // See:
224            // <https://github.com/MinaProtocol/mina/blob/e85cf6969e42060f69d305fb63df9b8d7215d3d7/src/lib/pickles/impls.ml#L94C1-L105C45>
225
226            let to_high_low = |fq: Fq| {
227                let [low, high @ ..] = field_to_bits::<Fq, 255>(fq);
228                [field_of_bits(&high), F::from(low)]
229            };
230            fields.extend(to_high_low(*self));
231        }
232    }
233}
234
235impl<F: FieldWitness, T: ToFieldElements<F>, const N: usize> ToFieldElements<F> for [T; N] {
236    fn to_field_elements(&self, fields: &mut Vec<F>) {
237        self.iter().for_each(|v| v.to_field_elements(fields));
238    }
239}
240
241impl<F: FieldWitness> ToFieldElements<F> for StagedLedgerHash<F> {
242    fn to_field_elements(&self, fields: &mut Vec<F>) {
243        let Self {
244            non_snark,
245            pending_coinbase_hash,
246        } = self;
247
248        let non_snark_digest = non_snark.digest();
249
250        const BITS: [u8; 8] = [1, 2, 4, 8, 16, 32, 64, 128];
251        fields.extend(
252            non_snark_digest
253                .iter()
254                .flat_map(|byte| BITS.iter().map(|bit| F::from((*byte & bit != 0) as u64))),
255        );
256
257        pending_coinbase_hash.to_field_elements(fields);
258    }
259}
260
261impl<F: FieldWitness> ToFieldElements<F> for ByteString {
262    fn to_field_elements(&self, fields: &mut Vec<F>) {
263        let slice: &[u8] = self;
264        slice.to_field_elements(fields);
265    }
266}
267
268impl<F: FieldWitness> ToFieldElements<F> for GroupAffine<F> {
269    fn to_field_elements(&self, fields: &mut Vec<F>) {
270        let Self {
271            x, y, infinity: _, ..
272        } = self;
273        y.to_field_elements(fields);
274        x.to_field_elements(fields);
275    }
276}
277
278impl<F: FieldWitness> ToFieldElements<F> for &'_ [u8] {
279    fn to_field_elements(&self, fields: &mut Vec<F>) {
280        const BITS: [u8; 8] = [1, 2, 4, 8, 16, 32, 64, 128];
281        fields.extend(
282            self.iter()
283                .flat_map(|byte| BITS.iter().map(|bit| F::from((*byte & bit != 0) as u64))),
284        );
285    }
286}
287
288impl<F: FieldWitness> ToFieldElements<F> for &'_ [bool] {
289    fn to_field_elements(&self, fields: &mut Vec<F>) {
290        fields.reserve(self.len());
291        fields.extend(self.iter().copied().map(F::from))
292    }
293}
294
295impl<F: FieldWitness> ToFieldElements<F> for bool {
296    fn to_field_elements(&self, fields: &mut Vec<F>) {
297        F::from(*self).to_field_elements(fields)
298    }
299}
300
301impl<F: FieldWitness> ToFieldElements<F> for u64 {
302    fn to_field_elements(&self, fields: &mut Vec<F>) {
303        F::from(*self).to_field_elements(fields)
304    }
305}
306
307impl<F: FieldWitness> ToFieldElements<F> for u32 {
308    fn to_field_elements(&self, fields: &mut Vec<F>) {
309        F::from(*self).to_field_elements(fields)
310    }
311}
312
313impl<F: FieldWitness, T: ToFieldElements<F>> ToFieldElements<F> for PointEvaluations<T> {
314    fn to_field_elements(&self, fields: &mut Vec<F>) {
315        let Self { zeta, zeta_omega } = self;
316        zeta.to_field_elements(fields);
317        zeta_omega.to_field_elements(fields);
318    }
319}
320
321impl<F: FieldWitness, T: ToFieldElements<F>> ToFieldElements<F> for ProofEvaluations<T> {
322    fn to_field_elements(&self, fields: &mut Vec<F>) {
323        let Self {
324            public: _,
325            w,
326            z,
327            s,
328            coefficients,
329            generic_selector,
330            poseidon_selector,
331            complete_add_selector,
332            mul_selector,
333            emul_selector,
334            endomul_scalar_selector,
335            range_check0_selector,
336            range_check1_selector,
337            foreign_field_add_selector,
338            foreign_field_mul_selector,
339            xor_selector,
340            rot_selector,
341            lookup_aggregation,
342            lookup_table,
343            lookup_sorted,
344            runtime_lookup_table,
345            runtime_lookup_table_selector,
346            xor_lookup_selector,
347            lookup_gate_lookup_selector,
348            range_check_lookup_selector,
349            foreign_field_mul_lookup_selector,
350        } = self;
351
352        let mut push = |value: &T| {
353            value.to_field_elements(fields);
354        };
355
356        w.iter().for_each(&mut push);
357        coefficients.iter().for_each(&mut push);
358        push(z);
359        s.iter().for_each(&mut push);
360        push(generic_selector);
361        push(poseidon_selector);
362        push(complete_add_selector);
363        push(mul_selector);
364        push(emul_selector);
365        push(endomul_scalar_selector);
366        range_check0_selector.as_ref().map(&mut push);
367        range_check1_selector.as_ref().map(&mut push);
368        foreign_field_add_selector.as_ref().map(&mut push);
369        foreign_field_mul_selector.as_ref().map(&mut push);
370        xor_selector.as_ref().map(&mut push);
371        rot_selector.as_ref().map(&mut push);
372        lookup_aggregation.as_ref().map(&mut push);
373        lookup_table.as_ref().map(&mut push);
374        lookup_sorted.iter().for_each(|v| {
375            v.as_ref().map(&mut push);
376        });
377        runtime_lookup_table.as_ref().map(&mut push);
378        runtime_lookup_table_selector.as_ref().map(&mut push);
379        xor_lookup_selector.as_ref().map(&mut push);
380        lookup_gate_lookup_selector.as_ref().map(&mut push);
381        range_check_lookup_selector.as_ref().map(&mut push);
382        foreign_field_mul_lookup_selector.as_ref().map(&mut push);
383    }
384}
385
386impl<F: FieldWitness> ToFieldElements<F> for AllEvals<F> {
387    fn to_field_elements(&self, fields: &mut Vec<F>) {
388        let Self {
389            ft_eval1,
390            evals:
391                EvalsWithPublicInput {
392                    evals,
393                    public_input,
394                },
395        } = self;
396
397        public_input.to_field_elements(fields);
398        evals.to_field_elements(fields);
399        ft_eval1.to_field_elements(fields);
400    }
401}
402
403impl<F: FieldWitness> ToFieldElements<F> for &[AllEvals<F>] {
404    fn to_field_elements(&self, fields: &mut Vec<F>) {
405        self.iter().for_each(|e| e.to_field_elements(fields))
406    }
407}
408
409impl<F: FieldWitness> ToFieldElements<F> for EpochData<F> {
410    fn to_field_elements(&self, fields: &mut Vec<F>) {
411        let Self {
412            ledger:
413                EpochLedger {
414                    hash,
415                    total_currency,
416                },
417            seed,
418            start_checkpoint,
419            lock_checkpoint,
420            epoch_length,
421        } = self;
422
423        hash.to_field_elements(fields);
424        total_currency.to_field_elements(fields);
425        seed.to_field_elements(fields);
426        start_checkpoint.to_field_elements(fields);
427        lock_checkpoint.to_field_elements(fields);
428        epoch_length.to_field_elements(fields);
429    }
430}
431
432impl<F: FieldWitness> ToFieldElements<F> for v2::MinaBaseProtocolConstantsCheckedValueStableV1 {
433    fn to_field_elements(&self, fields: &mut Vec<F>) {
434        let Self {
435            k,
436            slots_per_epoch,
437            slots_per_sub_window,
438            grace_period_slots,
439            delta,
440            genesis_state_timestamp,
441        } = self;
442
443        k.as_u32().to_field_elements(fields);
444        slots_per_epoch.as_u32().to_field_elements(fields);
445        slots_per_sub_window.as_u32().to_field_elements(fields);
446        grace_period_slots.as_u32().to_field_elements(fields);
447        delta.as_u32().to_field_elements(fields);
448        genesis_state_timestamp.as_u64().to_field_elements(fields);
449    }
450}
451
452impl ToFieldElements<Fp> for super::block::BlockchainState {
453    fn to_field_elements(&self, fields: &mut Vec<Fp>) {
454        let Self {
455            staged_ledger_hash,
456            genesis_ledger_hash,
457            ledger_proof_statement,
458            timestamp,
459            body_reference,
460        } = self;
461
462        staged_ledger_hash.to_field_elements(fields);
463        genesis_ledger_hash.to_field_elements(fields);
464        ledger_proof_statement.to_field_elements(fields);
465        timestamp.as_u64().to_field_elements(fields);
466        body_reference.to_field_elements(fields);
467    }
468}
469
470impl ToFieldElements<Fp> for super::block::consensus::ConsensusState {
471    fn to_field_elements(&self, fields: &mut Vec<Fp>) {
472        let super::block::consensus::ConsensusState {
473            blockchain_length,
474            epoch_count,
475            min_window_density,
476            sub_window_densities,
477            last_vrf_output,
478            total_currency,
479            curr_global_slot_since_hard_fork:
480                super::block::consensus::GlobalSlot {
481                    slot_number,
482                    slots_per_epoch,
483                },
484            global_slot_since_genesis,
485            staking_epoch_data,
486            next_epoch_data,
487            has_ancestor_in_same_checkpoint_window,
488            block_stake_winner,
489            block_creator,
490            coinbase_receiver,
491            supercharge_coinbase,
492        } = self;
493
494        blockchain_length.as_u32().to_field_elements(fields);
495        epoch_count.as_u32().to_field_elements(fields);
496        min_window_density.as_u32().to_field_elements(fields);
497        fields.extend(sub_window_densities.iter().map(|w| Fp::from(w.as_u32())));
498        last_vrf_output.to_field_elements(fields);
499        total_currency.as_u64().to_field_elements(fields);
500        slot_number.to_field_elements(fields);
501        slots_per_epoch.to_field_elements(fields);
502        global_slot_since_genesis.as_u32().to_field_elements(fields);
503        staking_epoch_data.to_field_elements(fields);
504        next_epoch_data.to_field_elements(fields);
505        has_ancestor_in_same_checkpoint_window.to_field_elements(fields);
506        block_stake_winner.to_field_elements(fields);
507        block_creator.to_field_elements(fields);
508        coinbase_receiver.to_field_elements(fields);
509        supercharge_coinbase.to_field_elements(fields);
510    }
511}
512
513impl ToFieldElements<Fp> for super::block::ProtocolStateBody {
514    fn to_field_elements(&self, fields: &mut Vec<Fp>) {
515        let Self {
516            genesis_state_hash,
517            blockchain_state,
518            consensus_state,
519            constants,
520        } = self;
521
522        genesis_state_hash.to_field_elements(fields);
523        blockchain_state.to_field_elements(fields);
524        consensus_state.to_field_elements(fields);
525        constants.to_field_elements(fields);
526    }
527}
528
529impl ToFieldElements<Fp> for TokenId {
530    fn to_field_elements(&self, fields: &mut Vec<Fp>) {
531        let Self(token_id) = self;
532        token_id.to_field_elements(fields);
533    }
534}
535
536impl ToFieldElements<Fp> for CompressedPubKey {
537    fn to_field_elements(&self, fields: &mut Vec<Fp>) {
538        let Self { x, is_odd } = self;
539        x.to_field_elements(fields);
540        is_odd.to_field_elements(fields);
541    }
542}
543
544impl ToFieldElements<Fp> for mina_signer::Signature {
545    fn to_field_elements(&self, fields: &mut Vec<Fp>) {
546        let Self { rx, s } = self;
547
548        rx.to_field_elements(fields);
549        let s_bits = field_to_bits::<_, 255>(*s);
550        s_bits.to_field_elements(fields);
551    }
552}
553
554impl ToFieldElements<Fp> for mina_signer::PubKey {
555    fn to_field_elements(&self, fields: &mut Vec<Fp>) {
556        let GroupAffine::<Fp> { x, y, .. } = self.point();
557        x.to_field_elements(fields);
558        y.to_field_elements(fields);
559    }
560}
561
562impl ToFieldElements<Fp> for transaction_union_payload::TransactionUnion {
563    fn to_field_elements(&self, fields: &mut Vec<Fp>) {
564        use transaction_union_payload::{Body, Common, TransactionUnionPayload};
565
566        let Self {
567            payload:
568                TransactionUnionPayload {
569                    common:
570                        Common {
571                            fee,
572                            fee_token,
573                            fee_payer_pk,
574                            nonce,
575                            valid_until,
576                            memo,
577                        },
578                    body:
579                        Body {
580                            tag,
581                            source_pk,
582                            receiver_pk,
583                            token_id,
584                            amount,
585                        },
586                },
587            signer,
588            signature,
589        } = self;
590
591        fee.to_field_elements(fields);
592        fee_token.to_field_elements(fields);
593        fee_payer_pk.to_field_elements(fields);
594        nonce.to_field_elements(fields);
595        valid_until.to_field_elements(fields);
596        memo.as_slice().to_field_elements(fields);
597        tag.to_untagged_bits().to_field_elements(fields);
598        source_pk.to_field_elements(fields);
599        receiver_pk.to_field_elements(fields);
600        token_id.to_field_elements(fields);
601        amount.to_field_elements(fields);
602        signer.to_field_elements(fields);
603        signature.to_field_elements(fields);
604    }
605}
606
607impl ToFieldElements<Fp> for pending_coinbase::StateStack {
608    fn to_field_elements(&self, fields: &mut Vec<Fp>) {
609        let Self { init, curr } = self;
610        init.to_field_elements(fields);
611        curr.to_field_elements(fields);
612    }
613}
614
615impl ToFieldElements<Fp> for pending_coinbase::Stack {
616    fn to_field_elements(&self, fields: &mut Vec<Fp>) {
617        let Self {
618            data: pending_coinbase::CoinbaseStack(data),
619            state,
620        } = self;
621
622        data.to_field_elements(fields);
623        state.to_field_elements(fields);
624    }
625}
626
627impl ToFieldElements<Fp> for TokenSymbol {
628    fn to_field_elements(&self, fields: &mut Vec<Fp>) {
629        let field: Fp = self.to_field();
630        field.to_field_elements(fields);
631    }
632}
633
634// TODO: De-deduplicate with ToInputs
635impl<F: FieldWitness> ToFieldElements<F> for crate::Timing {
636    fn to_field_elements(&self, fields: &mut Vec<F>) {
637        let TimingAsRecord {
638            is_timed,
639            initial_minimum_balance,
640            cliff_time,
641            cliff_amount,
642            vesting_period,
643            vesting_increment,
644        } = self.to_record();
645
646        F::from(is_timed).to_field_elements(fields);
647        F::from(initial_minimum_balance.as_u64()).to_field_elements(fields);
648        F::from(cliff_time.as_u32()).to_field_elements(fields);
649        F::from(cliff_amount.as_u64()).to_field_elements(fields);
650        F::from(vesting_period.as_u32()).to_field_elements(fields);
651        F::from(vesting_increment.as_u64()).to_field_elements(fields);
652    }
653}
654
655impl<F: FieldWitness> ToFieldElements<F> for crate::Permissions<crate::AuthRequired> {
656    fn to_field_elements(&self, fields: &mut Vec<F>) {
657        use crate::AuthOrVersion;
658
659        self.iter_as_bits(|bit| match bit {
660            AuthOrVersion::Auth(bit) => bit.to_field_elements(fields),
661            AuthOrVersion::Version(version) => version.to_field_elements(fields),
662        });
663    }
664}
665
666impl<F: FieldWitness> ToFieldElements<F> for crate::AuthRequired {
667    fn to_field_elements(&self, fields: &mut Vec<F>) {
668        // In OCaml `Controller.if_`
669        // push values in reverse order (because of OCaml evaluation order)
670        // <https://github.com/MinaProtocol/mina/blob/4283d70c8c5c1bd9eebb0d3e449c36fb0bf0c9af/src/lib/mina_base/permissions.ml#L174>
671        let crate::AuthRequiredEncoded {
672            constant,
673            signature_necessary,
674            signature_sufficient,
675        } = self.encode();
676
677        [signature_sufficient, signature_necessary, constant].to_field_elements(fields);
678    }
679}
680
681impl ToFieldElements<Fp> for Box<Account> {
682    fn to_field_elements(&self, fields: &mut Vec<Fp>) {
683        let Account {
684            public_key,
685            token_id: TokenId(token_id),
686            token_symbol,
687            balance,
688            nonce,
689            receipt_chain_hash: ReceiptChainHash(receipt_chain_hash),
690            delegate,
691            voting_for: VotingFor(voting_for),
692            timing,
693            permissions,
694            zkapp,
695        } = &**self;
696
697        // Important: Any changes here probably needs the same changes in `AccountUnhashed`
698        public_key.to_field_elements(fields);
699        token_id.to_field_elements(fields);
700        token_symbol.to_field_elements(fields);
701        balance.to_field_elements(fields);
702        nonce.to_field_elements(fields);
703        receipt_chain_hash.to_field_elements(fields);
704        let delegate = MyCow::borrow_or_else(delegate, CompressedPubKey::empty);
705        delegate.to_field_elements(fields);
706        voting_for.to_field_elements(fields);
707        timing.to_field_elements(fields);
708        permissions.to_field_elements(fields);
709        match zkapp.as_ref() {
710            Some(zkapp) => zkapp.hash(),
711            None => default_zkapp_hash(),
712        }
713        .to_field_elements(fields);
714    }
715}
716
717impl<F: FieldWitness> ToFieldElements<F> for crate::MerklePath {
718    fn to_field_elements(&self, fields: &mut Vec<F>) {
719        self.hash().to_field_elements(fields);
720    }
721}
722
723impl<F: FieldWitness, A: ToFieldElements<F>, B: ToFieldElements<F>> ToFieldElements<F> for (A, B) {
724    fn to_field_elements(&self, fields: &mut Vec<F>) {
725        let (a, b) = self;
726        a.to_field_elements(fields);
727        b.to_field_elements(fields);
728    }
729}
730
731impl<F: FieldWitness> ToFieldElements<F> for ReceiptChainHash {
732    fn to_field_elements(&self, fields: &mut Vec<F>) {
733        let Self(receipt_chain_hash) = self;
734        receipt_chain_hash.to_field_elements(fields);
735    }
736}
737
738impl<F: FieldWitness> ToFieldElements<F> for Sgn {
739    fn to_field_elements(&self, fields: &mut Vec<F>) {
740        let field: F = self.to_field();
741        field.to_field_elements(fields)
742    }
743}
744
745impl<F: FieldWitness, T: currency::Magnitude + ToFieldElements<F>> ToFieldElements<F>
746    for currency::Signed<T>
747{
748    fn to_field_elements(&self, fields: &mut Vec<F>) {
749        let Self { magnitude, sgn } = self;
750
751        magnitude.to_field_elements(fields);
752        sgn.to_field_elements(fields);
753    }
754}
755
756impl<F: FieldWitness> ToFieldElements<F> for PlonkVerificationKeyEvals<F> {
757    fn to_field_elements(&self, fields: &mut Vec<F>) {
758        let Self {
759            sigma,
760            coefficients,
761            generic,
762            psm,
763            complete_add,
764            mul,
765            emul,
766            endomul_scalar,
767        } = self;
768
769        sigma.iter().for_each(|s| s.to_field_elements(fields));
770        coefficients
771            .iter()
772            .for_each(|c| c.to_field_elements(fields));
773        generic.to_field_elements(fields);
774        psm.to_field_elements(fields);
775        complete_add.to_field_elements(fields);
776        mul.to_field_elements(fields);
777        emul.to_field_elements(fields);
778        endomul_scalar.to_field_elements(fields);
779    }
780}
781
782impl<F: FieldWitness, const N: usize> ToFieldElements<F> for crate::address::raw::Address<N> {
783    fn to_field_elements(&self, fields: &mut Vec<F>) {
784        let zero = F::zero();
785        let one = F::one();
786
787        fields.extend(
788            self.iter()
789                .map(|b| match b {
790                    crate::Direction::Left => zero,
791                    crate::Direction::Right => one,
792                })
793                .rev(),
794        );
795    }
796}
797
798// Implementation for references
799impl<F: FieldWitness, T: ToFieldElements<F>> ToFieldElements<F> for &T {
800    fn to_field_elements(&self, fields: &mut Vec<F>) {
801        (*self).to_field_elements(fields);
802    }
803}
804
805impl<F: FieldWitness> ToFieldElements<F> for InnerCurve<F> {
806    fn to_field_elements(&self, fields: &mut Vec<F>) {
807        let GroupAffine::<F> { x, y, .. } = self.to_affine();
808        x.to_field_elements(fields);
809        y.to_field_elements(fields);
810    }
811}
812
813impl<F: FieldWitness> ToFieldElements<F> for Boolean {
814    fn to_field_elements(&self, fields: &mut Vec<F>) {
815        self.to_field::<F>().to_field_elements(fields);
816    }
817}
818
819impl<F: FieldWitness> ToFieldElements<F> for CircuitVar<Boolean> {
820    fn to_field_elements(&self, fields: &mut Vec<F>) {
821        self.as_boolean().to_field_elements(fields);
822    }
823}
824
825impl<F: FieldWitness> ToFieldElements<F> for CircuitVar<Sgn> {
826    fn to_field_elements(&self, fields: &mut Vec<F>) {
827        match self {
828            CircuitVar::Constant(_) => (),
829            CircuitVar::Var(var) => var.to_field_elements(fields),
830        }
831    }
832}
833
834impl ToFieldElements<Fp> for StepMainStatement {
835    fn to_field_elements(&self, fields: &mut Vec<Fp>) {
836        let Self {
837            proof_state:
838                StepMainProofState {
839                    unfinalized_proofs,
840                    messages_for_next_step_proof,
841                },
842            messages_for_next_wrap_proof,
843        } = self;
844
845        unfinalized_proofs.to_field_elements(fields);
846        messages_for_next_step_proof.to_field_elements(fields);
847        messages_for_next_wrap_proof.to_field_elements(fields);
848    }
849}
850
851impl ToFieldElements<Fp> for PerProofWitness {
852    fn to_field_elements(&self, fields: &mut Vec<Fp>) {
853        let Self {
854            app_state,
855            wrap_proof,
856            proof_state,
857            prev_proof_evals,
858            prev_challenges,
859            prev_challenge_polynomial_commitments,
860            hack_feature_flags,
861        } = self;
862
863        assert!(app_state.is_none());
864
865        let push_affine = |g: GroupAffine<Fp>, fields: &mut Vec<Fp>| {
866            let GroupAffine::<Fp> { x, y, .. } = g;
867            x.to_field_elements(fields);
868            y.to_field_elements(fields);
869        };
870
871        let push_affines = |slice: &[GroupAffine<Fp>], fields: &mut Vec<Fp>| {
872            slice.iter().copied().for_each(|g| push_affine(g, fields))
873        };
874
875        let ProverProof {
876            commitments:
877                ProverCommitments {
878                    w_comm,
879                    z_comm,
880                    t_comm,
881                    lookup: _,
882                },
883            proof:
884                OpeningProof {
885                    lr,
886                    delta,
887                    z1,
888                    z2,
889                    sg,
890                },
891            evals: _,
892            ft_eval1: _,
893            prev_challenges: _,
894        } = wrap_proof;
895
896        for w in w_comm {
897            push_affines(&w.elems, fields);
898        }
899
900        push_affines(&z_comm.elems, fields);
901        push_affines(&t_comm.elems, fields);
902
903        for (a, b) in lr {
904            push_affine(*a, fields);
905            push_affine(*b, fields);
906        }
907
908        let shift = |f: Fq| <Fq as FieldWitness>::Shifting::of_field(f);
909
910        shift(*z1).to_field_elements(fields);
911        shift(*z2).to_field_elements(fields);
912
913        push_affines(&[*delta, *sg], fields);
914
915        let ProofState {
916            deferred_values:
917                DeferredValues {
918                    plonk:
919                        Plonk {
920                            alpha,
921                            beta,
922                            gamma,
923                            zeta,
924                            zeta_to_srs_length,
925                            zeta_to_domain_size,
926                            perm,
927                            lookup: _,
928                            feature_flags: _,
929                        },
930                    combined_inner_product,
931                    b,
932                    xi,
933                    bulletproof_challenges,
934                    branch_data,
935                },
936            sponge_digest_before_evaluations,
937            messages_for_next_wrap_proof: _,
938        } = proof_state;
939
940        two_u64_to_field::<Fp>(alpha).to_field_elements(fields);
941        two_u64_to_field::<Fp>(beta).to_field_elements(fields);
942        two_u64_to_field::<Fp>(gamma).to_field_elements(fields);
943        two_u64_to_field::<Fp>(zeta).to_field_elements(fields);
944
945        zeta_to_srs_length.to_field_elements(fields);
946        zeta_to_domain_size.to_field_elements(fields);
947        perm.to_field_elements(fields);
948        match hack_feature_flags {
949            OptFlag::Maybe => {
950                // This block is used only when proving zkapps using proof authorization.
951                // <https://github.com/MinaProtocol/mina/blob/126d4d2e3495d03adc8f9597113d58a7e8fbcfd0/src/lib/pickles/composition_types/composition_types.ml#L150-L155>
952                // <https://github.com/MinaProtocol/mina/blob/126d4d2e3495d03adc8f9597113d58a7e8fbcfd0/src/lib/pickles/per_proof_witness.ml#L149>
953                // <https://github.com/MinaProtocol/mina/blob/a51f09d09e6ae83362ea74eaca072c8e40d08b52/src/lib/pickles_types/plonk_types.ml#L104-L119>
954                // <https://github.com/MinaProtocol/mina/blob/a51f09d09e6ae83362ea74eaca072c8e40d08b52/src/lib/pickles_types/plonk_types.ml#L253-L303>
955
956                // the first 8 elements are the `Plonk_types.Features.typ`
957                // The last 2 elements are the `Plonk_types.Opt.typ`
958                // So far I've only seen proofs without feature flags.
959                // TODO: Are feature flags ever used in the server node ? Or they are only used in browser/client ?
960                let zeros: [u64; 10] = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
961                zeros.to_field_elements(fields);
962            }
963            OptFlag::Yes => unimplemented!(), // Is that used ?
964            OptFlag::No => {}
965        }
966
967        combined_inner_product.to_field_elements(fields);
968        b.to_field_elements(fields);
969        two_u64_to_field::<Fp>(xi).to_field_elements(fields);
970        bulletproof_challenges.to_field_elements(fields);
971
972        // Index
973        {
974            let v2::CompositionTypesBranchDataStableV1 {
975                proofs_verified,
976                domain_log2,
977            } = branch_data;
978            // <https://github.com/MinaProtocol/mina/blob/32a91613c388a71f875581ad72276e762242f802/src/lib/pickles_base/proofs_verified.ml#L58>
979            let proofs_verified = match proofs_verified {
980                v2::PicklesBaseProofsVerifiedStableV1::N0 => [Fp::zero(), Fp::zero()],
981                v2::PicklesBaseProofsVerifiedStableV1::N1 => [Fp::zero(), Fp::one()],
982                v2::PicklesBaseProofsVerifiedStableV1::N2 => [Fp::one(), Fp::one()],
983            };
984            let domain_log2: u64 = domain_log2.0.as_u8() as u64;
985
986            proofs_verified.to_field_elements(fields);
987            Fp::from(domain_log2).to_field_elements(fields);
988        }
989
990        four_u64_to_field::<Fp>(sponge_digest_before_evaluations)
991            .unwrap() // Never fail, `sponge_digest_before_evaluations` was previously a `Fp`
992            .to_field_elements(fields);
993
994        let AllEvals {
995            ft_eval1,
996            evals:
997                EvalsWithPublicInput {
998                    evals,
999                    public_input,
1000                },
1001        } = prev_proof_evals;
1002
1003        public_input.to_field_elements(fields);
1004        evals.to_field_elements(fields);
1005        match hack_feature_flags {
1006            OptFlag::Maybe => {
1007                // See above.
1008                // <https://github.com/MinaProtocol/mina/blob/a51f09d09e6ae83362ea74eaca072c8e40d08b52/src/lib/pickles_types/plonk_types.ml#L1028-L1046>
1009                let zeros: [u64; 57] = [0; 57];
1010                zeros.to_field_elements(fields);
1011            }
1012            OptFlag::Yes => unimplemented!(), // Is that used ?
1013            OptFlag::No => {}
1014        }
1015        ft_eval1.to_field_elements(fields);
1016        prev_challenges.to_field_elements(fields);
1017        push_affines(prev_challenge_polynomial_commitments, fields);
1018    }
1019}