1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
//! This module obtains the gates of a foreign field addition circuit.

use ark_ff::PrimeField;
use num_bigint::BigUint;
use o1_utils::foreign_field::ForeignFieldHelpers;

use crate::{
    alphas::Alphas,
    circuits::{
        argument::Argument,
        berkeley_columns::E,
        expr::Cache,
        gate::{CircuitGate, GateType},
        lookup::{
            self,
            tables::{GateLookupTable, LookupTable},
        },
        polynomials::{
            foreign_field_common::{BigUintForeignFieldHelpers, KimchiForeignElement},
            generic::GenericGateSpec,
        },
        wires::Wire,
    },
};

use super::circuitgates::ForeignFieldMul;

/// Number of gates in this gadget
pub const GATE_COUNT: usize = 1;

impl<F: PrimeField> CircuitGate<F> {
    /// Create foreign field multiplication gate
    ///     Inputs the starting row
    ///     Outputs tuple (next_row, circuit_gates) where
    ///       next_row      - next row after this gate
    ///       circuit_gates - vector of circuit gates comprising this gate
    pub fn create_foreign_field_mul(
        start_row: usize,
        foreign_field_modulus: &BigUint,
    ) -> (usize, Vec<Self>) {
        let neg_foreign_field_modulus = foreign_field_modulus.negate().to_field_limbs::<F>();
        let foreign_field_modulus = foreign_field_modulus.to_field_limbs::<F>();
        let circuit_gates = vec![
            CircuitGate {
                typ: GateType::ForeignFieldMul,
                wires: Wire::for_row(start_row),
                coeffs: vec![
                    foreign_field_modulus[2],
                    neg_foreign_field_modulus[0],
                    neg_foreign_field_modulus[1],
                    neg_foreign_field_modulus[2],
                ],
            },
            CircuitGate {
                typ: GateType::Zero,
                wires: Wire::for_row(start_row + 1),
                coeffs: vec![],
            },
        ];

        (start_row + circuit_gates.len(), circuit_gates)
    }

    /// Create foreign field multiplication gate by extending the existing gates
    pub fn extend_foreign_field_mul(
        gates: &mut Vec<Self>,
        curr_row: &mut usize,
        foreign_field_modulus: &BigUint,
    ) {
        let (next_row, circuit_gates) =
            Self::create_foreign_field_mul(*curr_row, foreign_field_modulus);
        *curr_row = next_row;
        gates.extend_from_slice(&circuit_gates);
    }

    pub fn extend_high_bounds(
        gates: &mut Vec<Self>,
        curr_row: &mut usize,
        foreign_field_modulus: &BigUint,
    ) {
        let r = gates.len();
        let hi_fmod = foreign_field_modulus.to_field_limbs::<F>()[2];
        let hi_limb: F = KimchiForeignElement::<F>::two_to_limb() - hi_fmod - F::one();
        let g = GenericGateSpec::Plus(hi_limb);
        CircuitGate::extend_generic(gates, curr_row, Wire::for_row(r), g.clone(), Some(g));
    }
}

// TODO: Check do we use this anywhere
pub fn circuit_gate_selector_index(typ: GateType) -> usize {
    match typ {
        GateType::ForeignFieldMul => 0,
        _ => panic!("invalid gate type"),
    }
}

/// Get vector of foreign field multiplication circuit gate types
pub fn circuit_gates() -> [GateType; GATE_COUNT] {
    [GateType::ForeignFieldMul]
}

/// Get combined constraints for a given foreign field multiplication circuit gate
pub fn circuit_gate_constraints<F: PrimeField>(
    typ: GateType,
    alphas: &Alphas<F>,
    cache: &mut Cache,
) -> E<F> {
    match typ {
        GateType::ForeignFieldMul => ForeignFieldMul::combined_constraints(alphas, cache),
        _ => panic!("invalid gate type"),
    }
}

/// Number of constraints for a given foreign field mul circuit gate type
pub fn circuit_gate_constraint_count<F: PrimeField>(typ: GateType) -> u32 {
    match typ {
        GateType::ForeignFieldMul => ForeignFieldMul::<F>::CONSTRAINTS,
        _ => panic!("invalid gate type"),
    }
}

/// Get the combined constraints for all foreign field multiplication circuit gates
pub fn combined_constraints<F: PrimeField>(alphas: &Alphas<F>, cache: &mut Cache) -> E<F> {
    ForeignFieldMul::combined_constraints(alphas, cache)
}

/// Get the foreign field multiplication lookup table
pub fn lookup_table<F: PrimeField>() -> LookupTable<F> {
    lookup::tables::get_table::<F>(GateLookupTable::RangeCheck)
}