Skip to main content

dory_pcs/primitives/
arithmetic.rs

1#![allow(missing_docs)]
2
3use super::{DoryDeserialize, DorySerialize};
4
5pub trait Field:
6    Sized
7    + Clone
8    + Copy
9    + PartialEq
10    + Send
11    + Sync
12    + DorySerialize
13    + DoryDeserialize
14    + std::ops::Add<Output = Self>
15    + std::ops::Sub<Output = Self>
16    + std::ops::Mul<Output = Self>
17    + std::ops::Neg<Output = Self>
18    + for<'a> std::ops::Add<&'a Self, Output = Self>
19    + for<'a> std::ops::Sub<&'a Self, Output = Self>
20    + for<'a> std::ops::Mul<&'a Self, Output = Self>
21{
22    fn zero() -> Self;
23    fn one() -> Self;
24    fn is_zero(&self) -> bool;
25
26    fn add(&self, rhs: &Self) -> Self;
27    fn sub(&self, rhs: &Self) -> Self;
28    fn mul(&self, rhs: &Self) -> Self;
29
30    fn inv(self) -> Option<Self>;
31
32    fn random() -> Self;
33
34    fn from_u64(val: u64) -> Self;
35    fn from_i64(val: i64) -> Self;
36}
37
38pub trait Group:
39    Sized
40    + Clone
41    + Copy
42    + PartialEq
43    + Send
44    + Sync
45    + DorySerialize
46    + DoryDeserialize
47    + std::ops::Add<Output = Self>
48    + std::ops::Sub<Output = Self>
49    + std::ops::Neg<Output = Self>
50    + for<'a> std::ops::Add<&'a Self, Output = Self>
51    + for<'a> std::ops::Sub<&'a Self, Output = Self>
52{
53    type Scalar: Field
54        + std::ops::Mul<Self, Output = Self>
55        + for<'a> std::ops::Mul<&'a Self, Output = Self>;
56
57    fn identity() -> Self;
58    fn add(&self, rhs: &Self) -> Self;
59    fn neg(&self) -> Self;
60    fn scale(&self, k: &Self::Scalar) -> Self;
61
62    fn random() -> Self;
63}
64
65pub trait PairingCurve: Clone {
66    type G1: Group;
67    type G2: Group;
68    type GT: Group; // Multiplicative subgroup F^* of the extension field
69
70    /// e : G1 × G2 → GT
71    fn pair(p: &Self::G1, q: &Self::G2) -> Self::GT;
72
73    /// Π e(p_i, q_i)
74    fn multi_pair(ps: &[Self::G1], qs: &[Self::G2]) -> Self::GT {
75        assert_eq!(
76            ps.len(),
77            qs.len(),
78            "multi_pair requires equal length vectors"
79        );
80
81        if ps.is_empty() {
82            return Self::GT::identity();
83        }
84
85        ps.iter()
86            .zip(qs.iter())
87            .fold(Self::GT::identity(), |acc, (p, q)| {
88                acc.add(&Self::pair(p, q))
89            })
90    }
91
92    /// Optimized multi-pairing when G2 points come from setup/generators
93    ///
94    /// This variant should be used when the G2 points are from the prover setup
95    /// (e.g., g2_vec generators). Backend implementations can optimize this by
96    /// caching prepared G2 points.
97    ///
98    /// # Parameters
99    /// - `ps`: G1 points (typically computed values like row commitments or v-vectors)
100    /// - `qs`: G2 points from setup (e.g., `setup.g2_vec[..n]`)
101    ///
102    /// # Returns
103    /// Product of pairings: Π e(p_i, q_i)
104    ///
105    /// # Default Implementation
106    /// Delegates to `multi_pair`
107    fn multi_pair_g2_setup(ps: &[Self::G1], qs: &[Self::G2]) -> Self::GT {
108        Self::multi_pair(ps, qs)
109    }
110
111    /// Optimized multi-pairing when G1 points are from the prover setup.
112    ///
113    /// This variant should be used when the G1 points are from the prover setup
114    /// (e.g., g1_vec generators). Backend implementations can optimize this by
115    /// caching prepared G1 points.
116    ///
117    /// # Parameters
118    /// - `ps`: G1 points from setup (e.g., `setup.g1_vec[..n]`)
119    /// - `qs`: G2 points (typically computed values like v-vectors)
120    ///
121    /// # Returns
122    /// Product of pairings: Π e(p_i, q_i)
123    ///
124    /// # Default Implementation
125    /// Delegates to `multi_pair`
126    fn multi_pair_g1_setup(ps: &[Self::G1], qs: &[Self::G2]) -> Self::GT {
127        Self::multi_pair(ps, qs)
128    }
129}
130
131/// Dory requires MSMs and vector scaling ops, hence we expose a trait for optimized versions of such routines.
132pub trait DoryRoutines<G: Group> {
133    fn msm(bases: &[G], scalars: &[G::Scalar]) -> G;
134
135    /// Fixed-base vectorized scalar multiplication where the same base is scaled by each scalar individually
136    /// Computes: \[base * scalars\[0\], base * scalars\[1\], ..., base * scalars\[n-1\]\]
137    fn fixed_base_vector_scalar_mul(base: &G, scalars: &[G::Scalar]) -> Vec<G>;
138
139    /// vs\[i\] = vs\[i\] + scalar * bases\[i\]
140    fn fixed_scalar_mul_bases_then_add(bases: &[G], vs: &mut [G], scalar: &G::Scalar);
141
142    /// vs\[i\] = scalar * vs\[i\] + addends\[i\]
143    fn fixed_scalar_mul_vs_then_add(vs: &mut [G], addends: &[G], scalar: &G::Scalar);
144
145    /// Fold field vectors: left\[i\] = left\[i\] * scalar + right\[i\]
146    fn fold_field_vectors(left: &mut [G::Scalar], right: &[G::Scalar], scalar: &G::Scalar) {
147        assert_eq!(left.len(), right.len(), "Lengths must match");
148        for i in 0..left.len() {
149            left[i] = left[i] * *scalar + right[i];
150        }
151    }
152}