Skip to main content

amcl_wrapper/
group_elem_g2.rs

1use crate::amcl::hmac;
2use crate::constants::{CurveOrder, GroupG2_SIZE, G2_COMP_BYTE_SIZE, HASH_TYPE};
3use crate::errors::{SerzDeserzError, ValueError};
4use crate::field_elem::{FieldElement, FieldElementVector};
5use crate::group_elem::{GroupElement, GroupElementVector};
6use crate::types::{GroupG2, FP, FP2};
7use crate::utils::{hash_msg, hash_to_field};
8use std::iter;
9use std::ops::{Add, AddAssign, Index, IndexMut, Mul, Neg, Sub, SubAssign};
10
11use core::fmt;
12use std::hash::{Hash, Hasher};
13use std::slice::Iter;
14
15use crate::rayon::iter::IntoParallelRefMutIterator;
16use rayon::prelude::*;
17use serde::de::{Deserialize, Deserializer, Error as DError, Visitor};
18use serde::ser::{Error as SError, Serialize, Serializer};
19use zeroize::Zeroize;
20
21/// Don't derive Copy trait as it can hold secret data and should not be accidentally copied
22#[derive(Clone)]
23pub struct G2 {
24    value: GroupG2,
25}
26
27impl fmt::Debug for G2 {
28    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
29        write!(f, "ECP2: [ {} ]", self.value.tostring())
30    }
31}
32
33impl GroupElement for G2 {
34    fn new() -> Self {
35        Self {
36            value: GroupG2::new(),
37        }
38    }
39
40    fn identity() -> Self {
41        let mut v = GroupG2::new();
42        v.inf();
43        Self { value: v }
44    }
45
46    /// This is an arbitrary choice. Any group element can be a generator
47    fn generator() -> Self {
48        GroupG2::generator().into()
49    }
50
51    fn is_identity(&self) -> bool {
52        self.value.is_infinity()
53    }
54
55    fn set_to_identity(&mut self) {
56        self.value.inf()
57    }
58
59    fn from_msg_hash(msg: &[u8]) -> Self {
60        GroupG2::mapit(&hash_msg(msg)).into()
61    }
62
63    impl_group_elem_byte_conversion_methods!(
64        GroupG2,
65        GroupG2_SIZE,
66        G2_COMP_BYTE_SIZE,
67        SerzDeserzError::G2BytesIncorrectSize
68    );
69
70    fn add_assign_(&mut self, b: &Self) {
71        self.value.add(&b.value);
72    }
73
74    fn sub_assign_(&mut self, b: &Self) {
75        self.value.sub(&b.value);
76    }
77
78    fn plus(&self, b: &Self) -> Self {
79        let mut sum = self.value.clone();
80        sum.add(&b.value);
81        sum.into()
82    }
83
84    fn minus(&self, b: &Self) -> Self {
85        let mut diff = self.value.clone();
86        diff.sub(&b.value);
87        diff.into()
88    }
89
90    fn scalar_mul_const_time(&self, a: &FieldElement) -> Self {
91        self.value.mul(&a.to_bignum()).into()
92    }
93
94    fn double(&self) -> Self {
95        let mut d = self.value.clone();
96        d.dbl();
97        d.into()
98    }
99
100    fn double_mut(&mut self) {
101        self.value.dbl();
102    }
103
104    /// Returns the string `infinity` if the element corresponds to a point at infinity
105    /// Returns `(x,y)` where both `x` and `y` are hex representations of FP2
106    fn to_hex(&self) -> String {
107        self.value.tostring()
108    }
109
110    fn from_hex(mut string: String) -> Result<Self, SerzDeserzError> {
111        if &string == "infinity" {
112            return Ok(Self::new());
113        }
114
115        // Need string as "(x,y)"
116        unbound_bounded_string!(string, '(', ')', SerzDeserzError::CannotParseG2);
117
118        let (x, y) = split_string_to_2_tuple!(string, SerzDeserzError::CannotParseG2);
119
120        let x_fp2 = parse_hex_as_FP2(x)?;
121        let y_fp2 = parse_hex_as_FP2(y)?;
122
123        Ok(Self {
124            value: GroupG2::new_fp2s(&x_fp2, &y_fp2),
125        })
126    }
127
128    fn negation(&self) -> Self {
129        let mut n = self.to_ecp();
130        n.neg();
131        n.into()
132    }
133
134    fn is_extension() -> bool {
135        return true;
136    }
137
138    fn has_correct_order(&self) -> bool {
139        return self.value.mul(&CurveOrder).is_infinity();
140    }
141}
142
143/// Parse given hex string as FP2
144pub fn parse_hex_as_FP2(mut string: String) -> Result<FP2, SerzDeserzError> {
145    // Need string as "[a,b]"
146    unbound_bounded_string!(string, '[', ']', SerzDeserzError::CannotParseFP2);
147
148    let (a, b) = split_string_to_2_tuple!(string, SerzDeserzError::CannotParseFP2);
149
150    let a_big = FieldElement::parse_hex_as_bignum(a)?;
151    let b_big = FieldElement::parse_hex_as_bignum(b)?;
152    Ok(FP2::new_bigs(&a_big, &b_big))
153}
154
155impl_group_elem_traits!(G2, GroupG2);
156
157impl_group_elem_serz!(G2, GroupG2, "G2");
158
159impl_group_elem_conversions!(G2, GroupG2, GroupG2_SIZE, G2_COMP_BYTE_SIZE);
160
161impl_group_elem_ops!(G2);
162
163impl_scalar_mul_ops!(G2);
164
165impl_group_element_lookup_table!(G2, G2LookupTable);
166
167/// Represents an element of the sub-group of the elliptic curve over prime the extension field
168impl_optmz_scalar_mul_ops!(G2, GroupG2, G2LookupTable);
169
170#[derive(Clone, Debug, Serialize, Deserialize)]
171pub struct G2Vector {
172    elems: Vec<G2>,
173}
174
175impl_group_elem_vec_ops!(G2, G2Vector);
176
177impl_group_elem_vec_product_ops!(G2, G2Vector, G2LookupTable);
178
179impl_group_elem_vec_conversions!(G2, G2Vector);
180
181impl G2 {
182    /// Computes sum of 2 scalar multiplications.
183    /// Faster than doing the scalar multiplications individually and then adding them. Uses lookup table
184    /// returns self*a + h*b
185    pub fn binary_scalar_mul(&self, h: &Self, a: &FieldElement, b: &FieldElement) -> Self {
186        // TODO: Replace with faster
187        let group_elems = iter::once(self).chain(iter::once(h));
188        let field_elems = iter::once(a).chain(iter::once(b));
189        G2Vector::multi_scalar_mul_const_time_without_precomputation(group_elems, field_elems)
190            .unwrap()
191    }
192
193    /// Hashes a byte slice to a group element according to the hash to curve point IETF standard
194    /// https://datatracker.ietf.org/doc/draft-irtf-cfrg-hash-to-curve/?include_text=1
195    /// `domain_separation_tag` should be unique between protocols as well as curves, eg. protocol A and
196    /// protocol B should use different `domain_separation_tag` while hashing to the same curve and
197    /// protocol A should use different `domain_separation_tag` while hashing to different curves.
198    /// Look at section 3.1 of the standard for more details
199    pub fn hash_to_curve(dst: &[u8], msg: &[u8]) -> G2 {
200        // Get 4 field elements as FP
201        let mut u: [FP; 4] = [FP::new(), FP::new(), FP::new(), FP::new()];
202        hash_to_field(hmac::MC_SHA2, HASH_TYPE, dst, msg, &mut u, 4);
203
204        // Create extension field elements (FP^2) as FP2
205        let fp2_1 = FP2::new_fps(&u[0], &u[1]);
206        let fp2_2 = FP2::new_fps(&u[2], &u[3]);
207
208        // Map each FP2 to a curve point and add the points
209        let mut P = GroupG2::map2point(&fp2_1);
210        let P1 = GroupG2::map2point(&fp2_2);
211        P.add(&P1);
212        // clear the cofactor of the addition point
213        P.cfp();
214
215        Self { value: P }
216    }
217}
218
219#[cfg(test)]
220mod test {
221    use super::*;
222
223    #[test]
224    fn test_parse_hex_for_FP2() {
225        // TODO:
226    }
227
228    #[test]
229    fn test_parse_bad_hex_for_FP2() {
230        // TODO:
231    }
232}