1use crate::{G1Affine, G2Affine, Gt, fp12::Fp12};
2use core::ops::{Add, AddAssign};
3use ff::Field;
4use subtle::{Choice, ConditionallySelectable};
5
6use blst::*;
7
8pub 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 #[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
124pub 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#[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}