@@ -10,14 +10,21 @@ use core::{
1010 ops:: { Add , Mul , Neg , Sub } ,
1111} ;
1212
13+ pub const FP_SERIALIZED_SIZE : usize = 48 ;
14+ pub const FP2_SERIALIZED_SIZE : usize = FP_SERIALIZED_SIZE * 2 ;
15+ pub const G1_SERIALIZED_SIZE : usize = FP_SERIALIZED_SIZE * 2 ;
16+ pub const G2_SERIALIZED_SIZE : usize = FP2_SERIALIZED_SIZE * 2 ;
17+
1318/// Bls12_381 provides access to curve and field arithmetics on the BLS12-381
1419/// curve.
1520pub struct Bls12_381 {
1621 env : Env ,
1722}
1823
24+ // This routine was copied with slight modification from the arkworks library:
25+ // https://github.com/arkworks-rs/algebra/blob/bf1c9b22b30325ef4df4f701dedcb6dea904c587/ff/src/biginteger/arithmetic.rs#L66-L79
1926fn sbb_for_sub_with_borrow ( a : & mut u64 , b : u64 , borrow : u8 ) -> u8 {
20- let tmp = ( 1u128 << 64 ) + ( * a as u128 ) - ( b as u128 ) - ( borrow as u128 ) ;
27+ let tmp = ( 1u128 << 64 ) + u128 :: from ( * a) - u128 :: from ( b ) - u128 :: from ( borrow) ;
2128 * a = tmp as u64 ;
2229 u8:: from ( tmp >> 64 == 0 )
2330}
@@ -52,22 +59,20 @@ impl<const N: usize> BigInt<N> {
5259 }
5360}
5461
55- impl < const N : usize , const M : usize > Into < BigInt < N > > for & BytesN < M > {
56- fn into ( self ) -> BigInt < N > {
57- const {
58- if M != N * 8 {
59- panic ! ( "BytesN::Into<BigInt> - length mismatch" )
60- }
62+ impl < const N : usize , const M : usize > From < & BytesN < M > > for BigInt < N > {
63+ fn from ( bytes : & BytesN < M > ) -> Self {
64+ if M != N * 8 {
65+ panic ! ( "BytesN::Into<BigInt> - length mismatch" )
6166 }
6267
63- let array = self . to_array ( ) ;
68+ let array = bytes . to_array ( ) ;
6469 let mut limbs = [ 0u64 ; N ] ;
6570 for i in 0 ..N {
6671 let start = i * 8 ;
6772 let end = start + 8 ;
68- let mut bytes = [ 0u8 ; 8 ] ;
69- bytes . copy_from_slice ( & array[ start..end] ) ;
70- limbs[ N - 1 - i] = u64:: from_be_bytes ( bytes ) ;
73+ let mut chunk = [ 0u8 ; 8 ] ;
74+ chunk . copy_from_slice ( & array[ start..end] ) ;
75+ limbs[ N - 1 - i] = u64:: from_be_bytes ( chunk ) ;
7176 }
7277 BigInt ( limbs)
7378 }
@@ -101,7 +106,7 @@ impl<const N: usize, const M: usize> Into<BigInt<N>> for &BytesN<M> {
101106/// ```
102107#[ derive( Clone ) ]
103108#[ repr( transparent) ]
104- pub struct G1Affine ( BytesN < 96 > ) ;
109+ pub struct G1Affine ( BytesN < G1_SERIALIZED_SIZE > ) ;
105110
106111/// `G2Affine` is a point in the G2 group (subgroup defined over the quadratic
107112/// extension field `Fq2`) of the BLS12-381 elliptic curve
@@ -121,7 +126,7 @@ pub struct G1Affine(BytesN<96>);
121126/// - sort_flag (bit 2): Must always be unset (0).
122127#[ derive( Clone ) ]
123128#[ repr( transparent) ]
124- pub struct G2Affine ( BytesN < 192 > ) ;
129+ pub struct G2Affine ( BytesN < G2_SERIALIZED_SIZE > ) ;
125130
126131/// `Fp` represents an element of the base field `Fq` of the BLS12-381 elliptic
127132/// curve
@@ -131,7 +136,7 @@ pub struct G2Affine(BytesN<192>);
131136/// field `Fp`. The value is serialized as a big-endian integer.
132137#[ derive( Clone ) ]
133138#[ repr( transparent) ]
134- pub struct Fp ( BytesN < 48 > ) ;
139+ pub struct Fp ( BytesN < FP_SERIALIZED_SIZE > ) ;
135140
136141/// `Fp2` represents an element of the quadratic extension field `Fq2` of the
137142/// BLS12-381 elliptic curve
@@ -143,7 +148,7 @@ pub struct Fp(BytesN<48>);
143148/// and imaginary components).
144149#[ derive( Clone ) ]
145150#[ repr( transparent) ]
146- pub struct Fp2 ( BytesN < 96 > ) ;
151+ pub struct Fp2 ( BytesN < FP2_SERIALIZED_SIZE > ) ;
147152
148153/// `Fr` represents an element in the BLS12-381 scalar field, which is a prime
149154/// field of order `r` (the order of the G1 and G2 groups). The struct is
@@ -153,26 +158,54 @@ pub struct Fp2(BytesN<96>);
153158#[ repr( transparent) ]
154159pub struct Fr ( U256 ) ;
155160
156- impl_bytesn_repr ! ( G1Affine , 96 ) ;
157- impl_bytesn_repr ! ( G2Affine , 192 ) ;
158- impl_bytesn_repr ! ( Fp , 48 ) ;
159- impl_bytesn_repr ! ( Fp2 , 96 ) ;
161+ impl_bytesn_repr ! ( G1Affine , G1_SERIALIZED_SIZE ) ;
162+ impl_bytesn_repr ! ( G2Affine , G2_SERIALIZED_SIZE ) ;
163+ impl_bytesn_repr ! ( Fp , FP_SERIALIZED_SIZE ) ;
164+ impl_bytesn_repr ! ( Fp2 , FP2_SERIALIZED_SIZE ) ;
160165
161166impl Fp {
162167 pub fn env ( & self ) -> & Env {
163168 self . 0 . env ( )
164169 }
165170
171+ fn checked_neg ( & self ) -> Option < Fp > {
172+ let fp_bigint: BigInt < 6 > = ( & self . 0 ) . into ( ) ;
173+ if fp_bigint. is_zero ( ) {
174+ return Some ( self . clone ( ) ) ;
175+ }
176+
177+ // BLS12-381 base field modulus
178+ const BLS12_381_MODULUS : [ u64 ; 6 ] = [
179+ 13402431016077863595 ,
180+ 2210141511517208575 ,
181+ 7435674573564081700 ,
182+ 7239337960414712511 ,
183+ 5412103778470702295 ,
184+ 1873798617647539866 ,
185+ ] ;
186+ let mut res = BigInt ( BLS12_381_MODULUS ) ;
187+
188+ // Compute modulus - value
189+ let borrow = res. sub_with_borrow ( & fp_bigint) ;
190+ if borrow {
191+ return None ;
192+ }
193+
194+ let mut bytes = [ 0u8 ; FP_SERIALIZED_SIZE ] ;
195+ res. copy_into_array ( & mut bytes) ;
196+ Some ( Fp :: from_array ( self . env ( ) , & bytes) )
197+ }
198+
166199 /// Maps to a `G1Affine` point via [simplified SWU
167200 /// mapping](https://www.rfc-editor.org/rfc/rfc9380.html#name-simplified-swu-for-ab-0)
168201 pub fn map_to_g1 ( & self ) -> G1Affine {
169202 self . env ( ) . crypto ( ) . bls12_381 ( ) . map_fp_to_g1 ( self )
170203 }
171204}
172205
173- impl Into < BigInt < 6 > > for Fp {
174- fn into ( self ) -> BigInt < 6 > {
175- let inner: Bytes = self . 0 . into ( ) ;
206+ impl From < Fp > for BigInt < 6 > {
207+ fn from ( fp : Fp ) -> Self {
208+ let inner: Bytes = fp . 0 . into ( ) ;
176209 let mut limbs = [ 0u64 ; 6 ] ;
177210 for i in 0 ..6u32 {
178211 let start = i * 8 ;
@@ -184,32 +217,22 @@ impl Into<BigInt<6>> for Fp {
184217 }
185218}
186219
187- impl Neg for Fp {
220+ impl Neg for & Fp {
188221 type Output = Fp ;
189222
190223 fn neg ( self ) -> Self :: Output {
191- let fp_bigint : BigInt < 6 > = ( & self . 0 ) . into ( ) ;
192- if fp_bigint . is_zero ( ) {
193- return self ;
224+ match self . checked_neg ( ) {
225+ Some ( v ) => v ,
226+ None => sdk_panic ! ( "invalid input - Fp is larger than the field modulus" ) ,
194227 }
228+ }
229+ }
195230
196- // BLS12-381 base field modulus
197- let mut res = BigInt ( [
198- 13402431016077863595 ,
199- 2210141511517208575 ,
200- 7435674573564081700 ,
201- 7239337960414712511 ,
202- 5412103778470702295 ,
203- 1873798617647539866 ,
204- ] ) ;
205- // Compute modulus - value
206- let borrow = res. sub_with_borrow ( & fp_bigint) ;
207- if borrow {
208- sdk_panic ! ( "invalid input - Fp is larger than the field modulus" )
209- }
210- let mut bytes = [ 0u8 ; 48 ] ;
211- res. copy_into_array ( & mut bytes) ;
212- Fp :: from_array ( & self . env ( ) , & bytes)
231+ impl Neg for Fp {
232+ type Output = Fp ;
233+
234+ fn neg ( self ) -> Self :: Output {
235+ ( & self ) . neg ( )
213236 }
214237}
215238
@@ -243,42 +266,84 @@ impl Mul<Fr> for G1Affine {
243266 }
244267}
245268
246- impl Neg for G1Affine {
269+ // G1Affine represents a point (X, Y) on the BLS12-381 curve where X, Y ∈ Fp
270+ // Negation of (X, Y) is defined as (X, -Y)
271+ impl Neg for & G1Affine {
247272 type Output = G1Affine ;
248273
249274 fn neg ( self ) -> Self :: Output {
250- let mut inner: Bytes = self . 0 . into ( ) ;
251- let y = Fp :: try_from_val ( inner. env ( ) , inner. slice ( 48 ..) . as_val ( ) ) . unwrap_optimized ( ) ;
275+ let mut inner: Bytes = ( & self . 0 ) . into ( ) ;
276+ let y = Fp :: try_from_val (
277+ inner. env ( ) ,
278+ inner. slice ( FP_SERIALIZED_SIZE as u32 ..) . as_val ( ) ,
279+ )
280+ . unwrap_optimized ( ) ;
252281 let neg_y = -y;
253- inner. copy_from_slice ( 48 , & neg_y. to_array ( ) ) ;
282+ inner. copy_from_slice ( FP_SERIALIZED_SIZE as u32 , & neg_y. to_array ( ) ) ;
254283 G1Affine :: from_bytes ( BytesN :: try_from_val ( inner. env ( ) , inner. as_val ( ) ) . unwrap_optimized ( ) )
255284 }
256285}
257286
287+ impl Neg for G1Affine {
288+ type Output = G1Affine ;
289+
290+ fn neg ( self ) -> Self :: Output {
291+ ( & self ) . neg ( )
292+ }
293+ }
294+
258295impl Fp2 {
259296 pub fn env ( & self ) -> & Env {
260297 self . 0 . env ( )
261298 }
262299
300+ // An Fp2 element is represented as c0 + c1 * X, where:
301+ // - c0, c1 are base field elements (Fp)
302+ // - X is the quadratic non-residue used to construct the field extension
303+ // The negation of c0 + c1 * X is (-c0) + (-c1) * X.
304+ fn checked_neg ( & self ) -> Option < Fp2 > {
305+ let mut inner = self . to_array ( ) ;
306+ let mut slice0 = [ 0 ; FP_SERIALIZED_SIZE ] ;
307+ let mut slice1 = [ 0 ; FP_SERIALIZED_SIZE ] ;
308+ slice0. copy_from_slice ( & inner[ 0 ..FP_SERIALIZED_SIZE ] ) ;
309+ slice1. copy_from_slice ( & inner[ FP_SERIALIZED_SIZE ..FP2_SERIALIZED_SIZE ] ) ;
310+
311+ // Convert both components to Fp and negate them
312+ let c0 = Fp :: from_array ( self . env ( ) , & slice0) ;
313+ let c1 = Fp :: from_array ( self . env ( ) , & slice1) ;
314+
315+ // If either component's negation fails, the whole operation fails
316+ let neg_c0 = c0. checked_neg ( ) ?;
317+ let neg_c1 = c1. checked_neg ( ) ?;
318+
319+ // Reconstruct the Fp2 element from negated components
320+ inner[ 0 ..FP_SERIALIZED_SIZE ] . copy_from_slice ( & neg_c0. to_array ( ) ) ;
321+ inner[ FP_SERIALIZED_SIZE ..FP2_SERIALIZED_SIZE ] . copy_from_slice ( & neg_c1. to_array ( ) ) ;
322+
323+ Some ( Fp2 :: from_array ( self . env ( ) , & inner) )
324+ }
325+
263326 pub fn map_to_g2 ( & self ) -> G2Affine {
264327 self . env ( ) . crypto ( ) . bls12_381 ( ) . map_fp2_to_g2 ( self )
265328 }
266329}
267330
331+ impl Neg for & Fp2 {
332+ type Output = Fp2 ;
333+
334+ fn neg ( self ) -> Self :: Output {
335+ match self . checked_neg ( ) {
336+ Some ( v) => v,
337+ None => sdk_panic ! ( "invalid input - Fp2 component is larger than the field modulus" ) ,
338+ }
339+ }
340+ }
341+
268342impl Neg for Fp2 {
269343 type Output = Fp2 ;
270344
271345 fn neg ( self ) -> Self :: Output {
272- let mut inner = self . to_array ( ) ;
273- let mut slice0 = [ 0 ; 48 ] ;
274- let mut slice1 = [ 0 ; 48 ] ;
275- slice0. copy_from_slice ( & inner[ 0 ..48 ] ) ;
276- slice1. copy_from_slice ( & inner[ 48 ..96 ] ) ;
277- let c0 = -Fp :: from_array ( self . env ( ) , & slice0) ;
278- let c1 = -Fp :: from_array ( self . env ( ) , & slice1) ;
279- inner[ 0 ..48 ] . copy_from_slice ( & c0. to_array ( ) ) ;
280- inner[ 48 ..96 ] . copy_from_slice ( & c1. to_array ( ) ) ;
281- Fp2 :: from_array ( self . env ( ) , & inner)
346+ ( & self ) . neg ( )
282347 }
283348}
284349
@@ -312,18 +377,32 @@ impl Mul<Fr> for G2Affine {
312377 }
313378}
314379
315- impl Neg for G2Affine {
380+ // G2Affine represents a point (X, Y) on the BLS12-381 quadratic extension curve where X, Y ∈ Fp2
381+ // Negation of (X, Y) is defined as (X, -Y)
382+ impl Neg for & G2Affine {
316383 type Output = G2Affine ;
317384
318385 fn neg ( self ) -> Self :: Output {
319- let mut inner: Bytes = self . 0 . into ( ) ;
320- let y = Fp2 :: try_from_val ( inner. env ( ) , inner. slice ( 96 ..) . as_val ( ) ) . unwrap_optimized ( ) ;
386+ let mut inner: Bytes = ( & self . 0 ) . into ( ) ;
387+ let y = Fp2 :: try_from_val (
388+ inner. env ( ) ,
389+ inner. slice ( FP2_SERIALIZED_SIZE as u32 ..) . as_val ( ) ,
390+ )
391+ . unwrap_optimized ( ) ;
321392 let neg_y = -y;
322- inner. copy_from_slice ( 96 , & neg_y. to_array ( ) ) ;
393+ inner. copy_from_slice ( FP2_SERIALIZED_SIZE as u32 , & neg_y. to_array ( ) ) ;
323394 G2Affine :: from_bytes ( BytesN :: try_from_val ( inner. env ( ) , inner. as_val ( ) ) . unwrap_optimized ( ) )
324395 }
325396}
326397
398+ impl Neg for G2Affine {
399+ type Output = G2Affine ;
400+
401+ fn neg ( self ) -> Self :: Output {
402+ ( & self ) . neg ( )
403+ }
404+ }
405+
327406impl Fr {
328407 pub fn env ( & self ) -> & Env {
329408 self . 0 . env ( )
0 commit comments