1
- use super :: field_extension:: BLS12381PrimeField ;
1
+ use super :: { field_extension:: BLS12381PrimeField , twist :: BLS12381TwistCurve } ;
2
2
use crate :: {
3
- elliptic_curve:: short_weierstrass:: {
4
- curves:: bls12_381:: curve:: BLS12381Curve , point:: ShortWeierstrassProjectivePoint ,
3
+ elliptic_curve:: {
4
+ short_weierstrass:: {
5
+ curves:: bls12_381:: {
6
+ curve:: BLS12381Curve , field_extension:: Degree2ExtensionField , sqrt,
7
+ } ,
8
+ point:: ShortWeierstrassProjectivePoint ,
9
+ traits:: Compress ,
10
+ } ,
11
+ traits:: IsEllipticCurve ,
5
12
} ,
6
13
field:: element:: FieldElement ,
7
14
} ;
@@ -12,95 +19,138 @@ use crate::{
12
19
traits:: ByteConversion ,
13
20
} ;
14
21
15
- pub type G1Point = ShortWeierstrassProjectivePoint < BLS12381Curve > ;
16
- pub type BLS12381FieldElement = FieldElement < BLS12381PrimeField > ;
17
-
18
- pub fn decompress_g1_point ( input_bytes : & mut [ u8 ; 48 ] ) -> Result < G1Point , ByteConversionError > {
19
- let first_byte = input_bytes. first ( ) . unwrap ( ) ;
20
- // We get the 3 most significant bits
21
- let prefix_bits = first_byte >> 5 ;
22
- let first_bit = ( prefix_bits & 4_u8 ) >> 2 ;
23
- // If first bit is not 1, then the value is not compressed.
24
- if first_bit != 1 {
25
- return Err ( ByteConversionError :: ValueNotCompressed ) ;
26
- }
27
- let second_bit = ( prefix_bits & 2_u8 ) >> 1 ;
28
- // If the second bit is 1, then the compressed point is the
29
- // point at infinity and we return it directly.
30
- if second_bit == 1 {
31
- return Ok ( G1Point :: neutral_element ( ) ) ;
22
+ type G1Point = ShortWeierstrassProjectivePoint < BLS12381Curve > ;
23
+ type BLS12381FieldElement = FieldElement < BLS12381PrimeField > ;
24
+
25
+ impl Compress for BLS12381Curve {
26
+ type G1Point = G1Point ;
27
+
28
+ type G2Point = <BLS12381TwistCurve as IsEllipticCurve >:: PointRepresentation ;
29
+
30
+ type Error = ByteConversionError ;
31
+
32
+ #[ cfg( feature = "alloc" ) ]
33
+ fn compress_g1_point ( point : & Self :: G1Point ) -> alloc:: vec:: Vec < u8 > {
34
+ if * point == G1Point :: neutral_element ( ) {
35
+ // point is at infinity
36
+ let mut x_bytes = alloc:: vec![ 0_u8 ; 48 ] ;
37
+ x_bytes[ 0 ] |= 1 << 7 ;
38
+ x_bytes[ 0 ] |= 1 << 6 ;
39
+ x_bytes
40
+ } else {
41
+ // point is not at infinity
42
+ let point_affine = point. to_affine ( ) ;
43
+ let x = point_affine. x ( ) ;
44
+ let y = point_affine. y ( ) ;
45
+
46
+ let mut x_bytes = x. to_bytes_be ( ) ;
47
+
48
+ // Set first bit to to 1 indicate this is compressed element.
49
+ x_bytes[ 0 ] |= 1 << 7 ;
50
+
51
+ let y_neg = core:: ops:: Neg :: neg ( y) ;
52
+ if y_neg. representative ( ) < y. representative ( ) {
53
+ x_bytes[ 0 ] |= 1 << 5 ;
54
+ }
55
+ x_bytes
56
+ }
32
57
}
33
- let third_bit = prefix_bits & 1_u8 ;
34
-
35
- let first_byte_without_control_bits = ( first_byte << 3 ) >> 3 ;
36
- input_bytes[ 0 ] = first_byte_without_control_bits;
37
-
38
- let x = BLS12381FieldElement :: from_bytes_be ( input_bytes) ?;
39
-
40
- // We apply the elliptic curve formula to know the y^2 value.
41
- let y_squared = x. pow ( 3_u16 ) + BLS12381FieldElement :: from ( 4 ) ;
42
-
43
- let ( y_sqrt_1, y_sqrt_2) = & y_squared. sqrt ( ) . ok_or ( ByteConversionError :: InvalidValue ) ?;
44
-
45
- // we call "negative" to the greate root,
46
- // if the third bit is 1, we take this grater value.
47
- // Otherwise, we take the second one.
48
- let y = match (
49
- y_sqrt_1. representative ( ) . cmp ( & y_sqrt_2. representative ( ) ) ,
50
- third_bit,
51
- ) {
52
- ( Ordering :: Greater , 0 ) => y_sqrt_2,
53
- ( Ordering :: Greater , _) => y_sqrt_1,
54
- ( Ordering :: Less , 0 ) => y_sqrt_1,
55
- ( Ordering :: Less , _) => y_sqrt_2,
56
- ( Ordering :: Equal , _) => y_sqrt_1,
57
- } ;
58
58
59
- let point =
60
- G1Point :: from_affine ( x, y. clone ( ) ) . map_err ( |_| ByteConversionError :: InvalidValue ) ?;
59
+ fn decompress_g1_point ( input_bytes : & mut [ u8 ; 48 ] ) -> Result < Self :: G1Point , Self :: Error > {
60
+ let first_byte = input_bytes. first ( ) . unwrap ( ) ;
61
+ // We get the 3 most significant bits
62
+ let prefix_bits = first_byte >> 5 ;
63
+ let first_bit = ( prefix_bits & 4_u8 ) >> 2 ;
64
+ // If first bit is not 1, then the value is not compressed.
65
+ if first_bit != 1 {
66
+ return Err ( ByteConversionError :: ValueNotCompressed ) ;
67
+ }
68
+ let second_bit = ( prefix_bits & 2_u8 ) >> 1 ;
69
+ // If the second bit is 1, then the compressed point is the
70
+ // point at infinity and we return it directly.
71
+ if second_bit == 1 {
72
+ return Ok ( G1Point :: neutral_element ( ) ) ;
73
+ }
74
+ let third_bit = prefix_bits & 1_u8 ;
61
75
62
- point
63
- . is_in_subgroup ( )
64
- . then_some ( point)
65
- . ok_or ( ByteConversionError :: PointNotInSubgroup )
66
- }
76
+ let first_byte_without_control_bits = ( first_byte << 3 ) >> 3 ;
77
+ input_bytes[ 0 ] = first_byte_without_control_bits;
78
+
79
+ let x = BLS12381FieldElement :: from_bytes_be ( input_bytes) ?;
80
+
81
+ // We apply the elliptic curve formula to know the y^2 value.
82
+ let y_squared = x. pow ( 3_u16 ) + BLS12381FieldElement :: from ( 4 ) ;
83
+
84
+ let ( y_sqrt_1, y_sqrt_2) = & y_squared. sqrt ( ) . ok_or ( ByteConversionError :: InvalidValue ) ?;
85
+
86
+ // we call "negative" to the greate root,
87
+ // if the third bit is 1, we take this grater value.
88
+ // Otherwise, we take the second one.
89
+ let y = match (
90
+ y_sqrt_1. representative ( ) . cmp ( & y_sqrt_2. representative ( ) ) ,
91
+ third_bit,
92
+ ) {
93
+ ( Ordering :: Greater , 0 ) => y_sqrt_2,
94
+ ( Ordering :: Greater , _) => y_sqrt_1,
95
+ ( Ordering :: Less , 0 ) => y_sqrt_1,
96
+ ( Ordering :: Less , _) => y_sqrt_2,
97
+ ( Ordering :: Equal , _) => y_sqrt_1,
98
+ } ;
99
+
100
+ let point =
101
+ G1Point :: from_affine ( x, y. clone ( ) ) . map_err ( |_| ByteConversionError :: InvalidValue ) ?;
102
+
103
+ point
104
+ . is_in_subgroup ( )
105
+ . then_some ( point)
106
+ . ok_or ( ByteConversionError :: PointNotInSubgroup )
107
+ }
108
+
109
+ #[ allow( unused) ]
110
+ fn decompress_g2_point ( input_bytes : & mut [ u8 ; 96 ] ) -> Result < Self :: G2Point , Self :: Error > {
111
+ let first_byte = input_bytes. first ( ) . unwrap ( ) ;
67
112
68
- #[ cfg( feature = "alloc" ) ]
69
- pub fn compress_g1_point ( point : & G1Point ) -> alloc:: vec:: Vec < u8 > {
70
- if * point == G1Point :: neutral_element ( ) {
71
- // point is at infinity
72
- let mut x_bytes = alloc:: vec![ 0_u8 ; 48 ] ;
73
- x_bytes[ 0 ] |= 1 << 7 ;
74
- x_bytes[ 0 ] |= 1 << 6 ;
75
- x_bytes
76
- } else {
77
- // point is not at infinity
78
- let point_affine = point. to_affine ( ) ;
79
- let x = point_affine. x ( ) ;
80
- let y = point_affine. y ( ) ;
81
-
82
- let mut x_bytes = x. to_bytes_be ( ) ;
83
-
84
- // Set first bit to to 1 indicate this is compressed element.
85
- x_bytes[ 0 ] |= 1 << 7 ;
86
-
87
- let y_neg = core:: ops:: Neg :: neg ( y) ;
88
- if y_neg. representative ( ) < y. representative ( ) {
89
- x_bytes[ 0 ] |= 1 << 5 ;
113
+ // We get the first 3 bits
114
+ let prefix_bits = first_byte >> 5 ;
115
+ let first_bit = ( prefix_bits & 4_u8 ) >> 2 ;
116
+ // If first bit is not 1, then the value is not compressed.
117
+ if first_bit != 1 {
118
+ return Err ( ByteConversionError :: InvalidValue ) ;
119
+ }
120
+ let second_bit = ( prefix_bits & 2_u8 ) >> 1 ;
121
+ // If the second bit is 1, then the compressed point is the
122
+ // point at infinity and we return it directly.
123
+ if second_bit == 1 {
124
+ return Ok ( Self :: G2Point :: neutral_element ( ) ) ;
90
125
}
91
- x_bytes
126
+
127
+ let first_byte_without_control_bits = ( first_byte << 3 ) >> 3 ;
128
+ input_bytes[ 0 ] = first_byte_without_control_bits;
129
+
130
+ let input0 = & input_bytes[ 48 ..] ;
131
+ let input1 = & input_bytes[ 0 ..48 ] ;
132
+ let x0 = BLS12381FieldElement :: from_bytes_be ( input0) . unwrap ( ) ;
133
+ let x1 = BLS12381FieldElement :: from_bytes_be ( input1) . unwrap ( ) ;
134
+ let x: FieldElement < Degree2ExtensionField > = FieldElement :: new ( [ x0, x1] ) ;
135
+
136
+ const VALUE : BLS12381FieldElement = BLS12381FieldElement :: from_hex_unchecked ( "4" ) ;
137
+ let b_param_qfe = FieldElement :: < Degree2ExtensionField > :: new ( [ VALUE , VALUE ] ) ;
138
+
139
+ let y = sqrt:: sqrt_qfe ( & ( x. pow ( 3_u64 ) + b_param_qfe) , 0 )
140
+ . ok_or ( ByteConversionError :: InvalidValue ) ?;
141
+
142
+ Self :: G2Point :: from_affine ( x, y) . map_err ( |_| ByteConversionError :: InvalidValue )
92
143
}
93
144
}
94
145
95
146
#[ cfg( test) ]
96
147
mod tests {
97
148
use super :: { BLS12381FieldElement , G1Point } ;
98
149
use crate :: elliptic_curve:: short_weierstrass:: curves:: bls12_381:: curve:: BLS12381Curve ;
150
+ use crate :: elliptic_curve:: short_weierstrass:: traits:: Compress ;
99
151
use crate :: elliptic_curve:: traits:: { FromAffine , IsEllipticCurve } ;
100
152
101
153
#[ cfg( feature = "alloc" ) ]
102
- use super :: compress_g1_point;
103
- use super :: decompress_g1_point;
104
154
use crate :: {
105
155
cyclic_group:: IsGroup , traits:: ByteConversion , unsigned_integer:: element:: UnsignedInteger ,
106
156
} ;
@@ -121,8 +171,10 @@ mod tests {
121
171
#[ cfg( feature = "alloc" ) ]
122
172
#[ test]
123
173
fn test_g1_compress_generator ( ) {
174
+ use crate :: elliptic_curve:: short_weierstrass:: traits:: Compress ;
175
+
124
176
let g = BLS12381Curve :: generator ( ) ;
125
- let mut compressed_g = compress_g1_point ( & g) ;
177
+ let mut compressed_g = BLS12381Curve :: compress_g1_point ( & g) ;
126
178
let first_byte = compressed_g. first ( ) . unwrap ( ) ;
127
179
128
180
let first_byte_without_control_bits = ( first_byte << 3 ) >> 3 ;
@@ -137,8 +189,10 @@ mod tests {
137
189
#[ cfg( feature = "alloc" ) ]
138
190
#[ test]
139
191
fn test_g1_compress_point_at_inf ( ) {
192
+ use crate :: elliptic_curve:: short_weierstrass:: traits:: Compress ;
193
+
140
194
let inf = G1Point :: neutral_element ( ) ;
141
- let compressed_inf = compress_g1_point ( & inf) ;
195
+ let compressed_inf = BLS12381Curve :: compress_g1_point ( & inf) ;
142
196
let first_byte = compressed_inf. first ( ) . unwrap ( ) ;
143
197
144
198
assert_eq ! ( * first_byte >> 6 , 3_u8 ) ;
@@ -147,11 +201,13 @@ mod tests {
147
201
#[ cfg( feature = "alloc" ) ]
148
202
#[ test]
149
203
fn test_compress_decompress_generator ( ) {
204
+ use crate :: elliptic_curve:: short_weierstrass:: traits:: Compress ;
205
+
150
206
let g = BLS12381Curve :: generator ( ) ;
151
- let compressed_g = compress_g1_point ( & g) ;
207
+ let compressed_g = BLS12381Curve :: compress_g1_point ( & g) ;
152
208
let mut compressed_g_slice: [ u8 ; 48 ] = compressed_g. try_into ( ) . unwrap ( ) ;
153
209
154
- let decompressed_g = decompress_g1_point ( & mut compressed_g_slice) . unwrap ( ) ;
210
+ let decompressed_g = BLS12381Curve :: decompress_g1_point ( & mut compressed_g_slice) . unwrap ( ) ;
155
211
156
212
assert_eq ! ( g, decompressed_g) ;
157
213
}
@@ -163,10 +219,10 @@ mod tests {
163
219
// calculate g point operate with itself
164
220
let g_2 = g. operate_with_self ( UnsignedInteger :: < 4 > :: from ( "2" ) ) ;
165
221
166
- let compressed_g2 = compress_g1_point ( & g_2) ;
222
+ let compressed_g2 = BLS12381Curve :: compress_g1_point ( & g_2) ;
167
223
let mut compressed_g2_slice: [ u8 ; 48 ] = compressed_g2. try_into ( ) . unwrap ( ) ;
168
224
169
- let decompressed_g2 = decompress_g1_point ( & mut compressed_g2_slice) . unwrap ( ) ;
225
+ let decompressed_g2 = BLS12381Curve :: decompress_g1_point ( & mut compressed_g2_slice) . unwrap ( ) ;
170
226
171
227
assert_eq ! ( g_2, decompressed_g2) ;
172
228
}
0 commit comments