Skip to main content

nam_blstrs/
pairing.rs

1use crate::{G1Affine, G2Affine, Gt, fp12::Fp12};
2use core::ops::{Add, AddAssign};
3use ff::Field;
4use subtle::{Choice, ConditionallySelectable};
5
6use blst::*;
7
8/// Execute a complete pairing operation `(p, q)`.
9pub fn pairing(p: &G1Affine, q: &G2Affine) -> Gt {
10    let mut tmp = blst_fp12::default();
11    unsafe { blst_miller_loop(&mut tmp, &q.0, &p.0) };
12
13    let mut out = blst_fp12::default();
14    unsafe { blst_final_exp(&mut out, &tmp) };
15
16    Gt(Fp12(out))
17}
18
19macro_rules! impl_pairing {
20    ($name:ident, $p:ty, $q:ty, $aggregate:ident, $aggregated:ident) => {
21        /// Aggregate pairings efficiently.
22        #[derive(Debug)]
23        pub struct $name {
24            v: Box<[u64]>,
25        }
26
27        impl $name {
28            pub fn new(hash_or_encode: bool, dst: &[u8]) -> Self {
29                let v: Vec<u64> = vec![0; unsafe { blst_pairing_sizeof() } / 8];
30                let mut obj = Self {
31                    v: v.into_boxed_slice(),
32                };
33                obj.init(hash_or_encode, dst);
34                obj
35            }
36
37            pub fn init(&mut self, hash_or_encode: bool, dst: &[u8]) {
38                unsafe { blst_pairing_init(self.ctx(), hash_or_encode, dst.as_ptr(), dst.len()) }
39            }
40
41            fn ctx(&mut self) -> *mut blst_pairing {
42                self.v.as_mut_ptr() as *mut blst_pairing
43            }
44
45            fn const_ctx(&self) -> *const blst_pairing {
46                self.v.as_ptr() as *const blst_pairing
47            }
48
49            pub fn aggregate(
50                &mut self,
51                pk: &$p,
52                sig: Option<&$q>,
53                msg: &[u8],
54                aug: &[u8],
55            ) -> Result<(), BLST_ERROR> {
56                let res = unsafe {
57                    $aggregate(
58                        self.ctx(),
59                        &pk.0,
60                        match sig {
61                            Some(sig) => &sig.0,
62                            None => std::ptr::null(),
63                        },
64                        msg.as_ptr(),
65                        msg.len(),
66                        aug.as_ptr(),
67                        aug.len(),
68                    )
69                };
70                if res == BLST_ERROR::BLST_SUCCESS {
71                    Ok(())
72                } else {
73                    Err(res)
74                }
75            }
76
77            pub fn aggregated(gtsig: &mut Gt, sig: &$q) {
78                unsafe { $aggregated(&mut (gtsig.0).0, &sig.0) }
79            }
80
81            pub fn commit(&mut self) {
82                unsafe { blst_pairing_commit(self.ctx()) }
83            }
84
85            pub fn merge(&mut self, ctx1: &Self) -> Result<(), BLST_ERROR> {
86                let res = unsafe { blst_pairing_merge(self.ctx(), ctx1.const_ctx()) };
87                if res == BLST_ERROR::BLST_SUCCESS {
88                    Ok(())
89                } else {
90                    Err(res)
91                }
92            }
93
94            pub fn finalverify(&self, gtsig: Option<&Gt>) -> bool {
95                unsafe {
96                    blst_pairing_finalverify(
97                        self.const_ctx(),
98                        match gtsig {
99                            Some(ref gtsig) => &(gtsig.0).0,
100                            None => std::ptr::null(),
101                        },
102                    )
103                }
104            }
105        }
106    };
107}
108
109impl_pairing!(
110    PairingG1G2,
111    G1Affine,
112    G2Affine,
113    blst_pairing_aggregate_pk_in_g1,
114    blst_aggregated_in_g2
115);
116impl_pairing!(
117    PairingG2G1,
118    G2Affine,
119    G1Affine,
120    blst_pairing_aggregate_pk_in_g2,
121    blst_aggregated_in_g1
122);
123
124/// Returns true if all provided messages are distinctly unique, false otherwise.
125pub fn unique_messages(msgs: &[&[u8]]) -> bool {
126    let n_elems = msgs.len();
127
128    if n_elems == 1 {
129        return true;
130    } else if n_elems == 2 {
131        return msgs[0] != msgs[1];
132    }
133
134    let mut v: Vec<u64> = vec![0; unsafe { blst_uniq_sizeof(n_elems) } / 8];
135    let ctx = v.as_mut_ptr() as *mut blst_uniq;
136
137    unsafe { blst_uniq_init(ctx) };
138
139    for msg in msgs.iter() {
140        if !unsafe { blst_uniq_test(ctx, msg.as_ptr(), msg.len()) } {
141            return false;
142        }
143    }
144
145    true
146}
147
148/// Represents results of a Miller loop, one of the most expensive portions
149/// of the pairing function. `MillerLoopResult`s cannot be compared with each
150/// other until `.final_exponentiation()` is called, which is also expensive.
151#[derive(Copy, Clone, Debug, PartialEq, Eq)]
152#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
153#[repr(transparent)]
154pub struct MillerLoopResult(pub(crate) Fp12);
155
156impl ConditionallySelectable for MillerLoopResult {
157    fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
158        MillerLoopResult(Fp12::conditional_select(&a.0, &b.0, choice))
159    }
160}
161
162impl Default for MillerLoopResult {
163    fn default() -> Self {
164        MillerLoopResult(Fp12::ONE)
165    }
166}
167
168impl pairing_lib::MillerLoopResult for MillerLoopResult {
169    type Gt = Gt;
170
171    fn final_exponentiation(&self) -> Gt {
172        let mut out = blst_fp12::default();
173        unsafe { blst_final_exp(&mut out, &(self.0).0) };
174        Gt(Fp12(out))
175    }
176}
177
178impl<'b> Add<&'b MillerLoopResult> for &MillerLoopResult {
179    type Output = MillerLoopResult;
180
181    #[inline]
182    #[allow(clippy::suspicious_arithmetic_impl)]
183    fn add(self, rhs: &'b MillerLoopResult) -> MillerLoopResult {
184        MillerLoopResult(self.0 * rhs.0)
185    }
186}
187
188impl_add!(MillerLoopResult);
189
190impl AddAssign<MillerLoopResult> for MillerLoopResult {
191    #[inline]
192    #[allow(clippy::suspicious_op_assign_impl)]
193    fn add_assign(&mut self, rhs: MillerLoopResult) {
194        self.0 *= &rhs.0;
195    }
196}
197
198impl<'b> AddAssign<&'b MillerLoopResult> for MillerLoopResult {
199    #[inline]
200    #[allow(clippy::op_ref)]
201    fn add_assign(&mut self, rhs: &'b MillerLoopResult) {
202        *self = &*self + rhs;
203    }
204}