@@ -26,13 +26,12 @@ pub const G1 = struct {
2626 .z = .zero ,
2727 };
2828
29- fn fromBytesInternal (input : * const [64 ]u8 ) ! G1 {
29+ fn fromBytesInternal (input : * const [64 ]u8 , endian : std.builtin.Endian ) ! G1 {
3030 if (std .mem .allEqual (u8 , input , 0 )) return .zero ;
31-
3231 var flags : Flags = undefined ;
3332 return .{
34- .x = try .fromBytes (input [0.. 32], null ),
35- .y = try .fromBytes (input [32.. 64], & flags ),
33+ .x = try .fromBytes (input [0.. 32], endian , null ),
34+ .y = try .fromBytes (input [32.. 64], endian , & flags ),
3635 .z = if (flags .is_inf ) .zero else .one ,
3736 };
3837 }
@@ -49,8 +48,8 @@ pub const G1 = struct {
4948 // G1 has prime order so we do not need a subgroup membership check.
5049 }
5150
52- pub fn fromBytes (input : * const [64 ]u8 ) ! G1 {
53- var g1 = try fromBytesInternal (input );
51+ pub fn fromBytes (input : * const [64 ]u8 , endian : std.builtin.Endian ) ! G1 {
52+ var g1 = try fromBytesInternal (input , endian );
5453 if (g1 .isZero ()) return g1 ;
5554
5655 g1 .x .toMont ();
@@ -62,19 +61,17 @@ pub const G1 = struct {
6261 return g1 ;
6362 }
6463
65- fn toBytes (p : G1 , out : * [64 ]u8 ) void {
64+ fn toBytes (p : G1 , out : * [64 ]u8 , endian : std.builtin.Endian ) void {
6665 if (p .isZero ()) {
67- // no flags
68- @memset (out , 0 );
66+ @memset (out , 0 ); // no flags
6967 return ;
7068 }
7169
7270 var r = p .toAffine ();
7371 r .x .fromMont ();
7472 r .y .fromMont ();
75-
76- r .x .toBytes (out [0.. 32]);
77- r .y .toBytes (out [32.. 64]);
73+ r .x .toBytes (out [0.. 32], endian );
74+ r .y .toBytes (out [32.. 64], endian );
7875 }
7976
8077 fn isZero (p : G1 ) bool {
@@ -99,8 +96,8 @@ pub const G1 = struct {
9996 };
10097 }
10198
102- pub fn compress (out : * [32 ]u8 , input : * const [64 ]u8 ) ! void {
103- const p : G1 = try .fromBytesInternal (input );
99+ pub fn compress (out : * [32 ]u8 , input : * const [64 ]u8 , endian : std.builtin.Endian ) ! void {
100+ const p : G1 = try .fromBytesInternal (input , endian );
104101
105102 const is_inf = p .isZero ();
106103 const flag_inf = input [32 ] & Flags .INF ;
@@ -115,33 +112,37 @@ pub const G1 = struct {
115112
116113 const is_neg = p .y .isNegative ();
117114 @memcpy (out , input [0.. 32]);
118- if (is_neg ) out [0 ] |= Flags .NEG ;
115+ const offset : u32 = switch (endian ) {
116+ .little = > 31 ,
117+ .big = > 0 ,
118+ };
119+ if (is_neg ) out [offset ] |= Flags .NEG ;
119120 return ;
120121 }
121122
122- pub fn decompress (out : * [64 ]u8 , input : * const [32 ]u8 ) ! void {
123+ pub fn decompress (out : * [64 ]u8 , input : * const [32 ]u8 , endian : std.builtin.Endian ) ! void {
123124 // All zeroes input, all zeroes out, no flags.
124125 if (std .mem .allEqual (u8 , input , 0 )) return @memset (out , 0 );
125126
126127 var flags : Flags = undefined ;
127- var x : Fp = try .fromBytes (input , & flags );
128+ const x : Fp = try .fromBytes (input , endian , & flags );
128129
129130 // If the point at infinity flag is set, return the point at infinity without any
130131 // checks on the coordinates (X, Y) and no flags set.
131132 if (flags .is_inf ) return @memset (out , 0 );
132133
134+ var xm = x ;
135+ xm .toMont ();
133136 // y^2 = x^3+b
134- x .toMont ();
135- const x3b = x .sq ().mul (x ).add (Fp .constants .b_mont );
137+ const x3b = xm .sq ().mul (xm ).add (Fp .constants .b_mont );
136138 var y = try x3b .sqrt ();
137139 y .fromMont ();
138140 if (flags .is_neg != y .isNegative ()) {
139141 y .negateNotMontgomery (y ); // correct the sign to the requested one
140142 }
141143
142- @memcpy (out [0.. 32], input );
143- out [0 ] &= Flags .MASK ;
144- y .toBytes (out [32.. 64]);
144+ x .toBytes (out [0.. 32], endian );
145+ y .toBytes (out [32.. 64], endian );
145146 // no flags on y
146147 }
147148
@@ -198,13 +199,13 @@ pub const G2 = struct {
198199 .z = .zero ,
199200 };
200201
201- fn fromBytesInternal (input : * const [128 ]u8 ) ! G2 {
202+ fn fromBytesInternal (input : * const [128 ]u8 , endian : std.builtin.Endian ) ! G2 {
202203 if (std .mem .allEqual (u8 , input , 0 )) return .zero ;
203204
204205 var flags : Flags = undefined ;
205206 return .{
206- .x = try .fromBytes (input [0.. 64], null ),
207- .y = try .fromBytes (input [64.. 128], & flags ),
207+ .x = try .fromBytes (input [0.. 64], endian , null ),
208+ .y = try .fromBytes (input [64.. 128], endian , & flags ),
208209 .z = if (flags .is_inf ) .zero else .one ,
209210 };
210211 }
@@ -232,8 +233,8 @@ pub const G2 = struct {
232233 if (! l .eql (r )) return error .NotWellFormed ;
233234 }
234235
235- fn fromBytes (input : * const [128 ]u8 ) ! G2 {
236- var g2 : G2 = try .fromBytesInternal (input );
236+ fn fromBytes (input : * const [128 ]u8 , endian : std.builtin.Endian ) ! G2 {
237+ var g2 : G2 = try .fromBytesInternal (input , endian );
237238 if (g2 .isZero ()) return g2 ;
238239
239240 g2 .x .toMont ();
@@ -249,8 +250,8 @@ pub const G2 = struct {
249250 return p .z .isZero ();
250251 }
251252
252- pub fn compress (out : * [64 ]u8 , input : * const [128 ]u8 ) ! void {
253- const p : G2 = try .fromBytesInternal (input );
253+ pub fn compress (out : * [64 ]u8 , input : * const [128 ]u8 , endian : std.builtin.Endian ) ! void {
254+ const p : G2 = try .fromBytesInternal (input , endian );
254255
255256 const is_inf = p .isZero ();
256257 const flag_inf = input [64 ] & Flags .INF ;
@@ -263,33 +264,37 @@ pub const G2 = struct {
263264 }
264265
265266 const is_neg = p .y .isNegative ();
266- @memcpy (out , input [0.. 64]);
267- if (is_neg ) out [0 ] |= Flags .NEG ;
267+ p .x .toBytes (out , endian );
268+ const offset : u32 = switch (endian ) {
269+ .little = > 63 ,
270+ .big = > 0 ,
271+ };
272+ if (is_neg ) out [offset ] |= Flags .NEG ;
268273 return ;
269274 }
270275
271- pub fn decompress (out : * [128 ]u8 , input : * const [64 ]u8 ) ! void {
276+ pub fn decompress (out : * [128 ]u8 , input : * const [64 ]u8 , endian : std.builtin.Endian ) ! void {
272277 if (std .mem .allEqual (u8 , input , 0 )) return @memset (out , 0 );
273278
274279 var flags : Flags = undefined ;
275- var x : Fp2 = try .fromBytes (input , & flags );
280+ const x : Fp2 = try .fromBytes (input , endian , & flags );
276281
277282 // no flags
278283 if (flags .is_inf ) return @memset (out , 0 );
279284
280285 // y^2 = x^3+b
281- x .toMont ();
282- const x3b = x .sq ().mul (x ).add (Fp2 .constants .twist_b_mont );
286+ var xm = x ;
287+ xm .toMont ();
288+ const x3b = xm .sq ().mul (xm ).add (Fp2 .constants .twist_b_mont );
283289 var y = try x3b .sqrt ();
284290
285291 y .fromMont ();
286292 if (flags .is_neg != y .isNegative ()) {
287293 y .negateNotMontgomery (y );
288294 }
289295
290- @memcpy (out [0.. 64], input );
291- out [0 ] &= Flags .MASK ;
292- y .toBytes (out [64.. 128]);
296+ x .toBytes (out [0.. 64], endian );
297+ y .toBytes (out [64.. 128], endian );
293298 }
294299
295300 fn eql (a : G2 , b : G2 ) bool {
@@ -479,31 +484,34 @@ fn mulScalar(a: anytype, scalar: u256) @TypeOf(a) {
479484 return r ;
480485}
481486
482- pub fn addSyscall (out : * [64 ]u8 , input : * const [128 ]u8 ) ! void {
483- const x : G1 = try .fromBytes (input [0.. 64]);
484- const y : G1 = try .fromBytes (input [64.. 128]);
487+ pub fn addSyscall (out : * [64 ]u8 , input : * const [128 ]u8 , endian : std.builtin.Endian ) ! void {
488+ const x : G1 = try .fromBytes (input [0.. 64], endian );
489+ const y : G1 = try .fromBytes (input [64.. 128], endian );
485490 const result = x .affineAdd (y );
486- result .toBytes (out );
491+ result .toBytes (out , endian );
487492}
488493
489- pub fn mulSyscall (out : * [64 ]u8 , input : * const [96 ]u8 ) ! void {
490- const a : G1 = try .fromBytes (input [0.. 64]);
494+ pub fn mulSyscall (out : * [64 ]u8 , input : * const [96 ]u8 , endian : std.builtin.Endian ) ! void {
495+ const a : G1 = try .fromBytes (input [0.. 64], endian );
491496 // Scalar is provided in big-endian and we do *not* validate it.
492- const b : u256 = @bitCast (Fp .byteSwap (input [64.. ][0.. 32].* ));
497+ const b : u256 = @bitCast (switch (endian ) {
498+ .big = > Fp .byteSwap (input [64.. ][0.. 32].* ),
499+ .little = > input [64.. ][0.. 32].* ,
500+ });
493501 const result = mulScalar (a , b );
494- result .toBytes (out );
502+ result .toBytes (out , endian );
495503}
496504
497- pub fn pairingSyscall (out : * [32 ]u8 , input : []const u8 ) ! void {
505+ pub fn pairingSyscall (out : * [32 ]u8 , input : []const u8 , endian : std.builtin.Endian ) ! void {
498506 const num_elements = input .len / 192 ;
499507
500508 var p : std .BoundedArray (G1 , pairing .BATCH_SIZE ) = .{};
501509 var q : std .BoundedArray (G2 , pairing .BATCH_SIZE ) = .{};
502510
503511 var r : Fp12 = .one ;
504512 for (0.. num_elements ) | i | {
505- const a : G1 = try .fromBytes (input [i * 192 .. ][0.. 64]);
506- const b : G2 = try .fromBytes (input [i * 192 .. ][64.. ][0.. 128]);
513+ const a : G1 = try .fromBytes (input [i * 192 .. ][0.. 64], endian );
514+ const b : G2 = try .fromBytes (input [i * 192 .. ][64.. ][0.. 128], endian );
507515
508516 // Skip any pair where either A or B are points at infinity.
509517 if (a .isZero () or b .isZero ()) continue ;
@@ -521,7 +529,11 @@ pub fn pairingSyscall(out: *[32]u8, input: []const u8) !void {
521529 }
522530
523531 r = pairing .finalExp (r );
524- // Output is 0 or 1 as a big-endian u256.
532+ // Output is 0 or 1 as a u256.
525533 @memset (out , 0 );
526- if (r .isOne ()) out [31 ] = 1 ;
534+ const offset : u32 = switch (endian ) {
535+ .little = > 0 ,
536+ .big = > 31 ,
537+ };
538+ if (r .isOne ()) out [offset ] = 1 ;
527539}
0 commit comments