1use amcl::bls381::{big::Big, bls381::utils::deserialize_g1, fp::FP};
2use generic_array::GenericArray;
3use num::{BigUint, Num, Zero};
4use serde::{Deserialize, Serialize};
5use typenum::{U48, U94};
6
7use super::{FieldType, FpOpField, SwCurve, WeierstrassParameters};
8use crate::{
9 params::{FieldParameters, NumLimbs},
10 CurveType, EllipticCurveParameters,
11};
12
13use crate::{AffinePoint, EllipticCurve};
15
16const COMPRESSION_FLAG: u8 = 0b_1000_0000;
18const Y_IS_ODD_FLAG: u8 = 0b_0010_0000;
19
20#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
21pub struct Bls12381Parameters;
23
24pub type Bls12381 = SwCurve<Bls12381Parameters>;
25
26#[derive(Debug, Default, Clone, Copy, PartialEq, Serialize, Deserialize)]
27pub struct Bls12381BaseField;
29
30impl FieldParameters for Bls12381BaseField {
31 const NB_LIMBS: usize = 48;
35
36 const MODULUS: &'static [u8] = &[
37 171, 170, 255, 255, 255, 255, 254, 185, 255, 255, 83, 177, 254, 255, 171, 30, 36, 246, 176,
38 246, 160, 210, 48, 103, 191, 18, 133, 243, 132, 75, 119, 100, 215, 172, 75, 67, 182, 167,
39 27, 75, 154, 230, 127, 57, 234, 17, 1, 26,
40 ];
41
42 const WITNESS_OFFSET: usize = 1usize << 15;
44
45 fn modulus() -> BigUint {
46 BigUint::from_str_radix(
47 "4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272559787",
48 10,
49 )
50 .unwrap()
51 }
52}
53
54impl FpOpField for Bls12381BaseField {
55 const FIELD_TYPE: FieldType = FieldType::Bls12381;
56}
57
58impl NumLimbs for Bls12381BaseField {
59 type Limbs = U48;
60 type Witness = U94;
61}
62
63impl EllipticCurveParameters for Bls12381Parameters {
64 type BaseField = Bls12381BaseField;
65 const CURVE_TYPE: CurveType = CurveType::Bls12381;
66}
67
68impl WeierstrassParameters for Bls12381Parameters {
69 const A: GenericArray<u8, U48> = GenericArray::from_array([
72 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
73 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
74 ]);
75
76 const B: GenericArray<u8, U48> = GenericArray::from_array([
77 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
78 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
79 ]);
80
81 fn generator() -> (BigUint, BigUint) {
82 let x = BigUint::from_str_radix(
83 "3685416753713387016781088315183077757961620795782546409894578378688607592378376318836054947676345821548104185464507",
84 10,
85 )
86 .unwrap();
87 let y = BigUint::from_str_radix(
88 "1339506544944476473020471379941921221584933875938349620426543736416511423956333506472724655353366534992391756441569",
89 10,
90 )
91 .unwrap();
92 (x, y)
93 }
94
95 fn prime_group_order() -> num::BigUint {
98 BigUint::from_str_radix(
99 "52435875175126190479447740508185965837690552500527637822603658699938581184513",
100 10,
101 )
102 .unwrap()
103 }
104
105 fn a_int() -> BigUint {
106 BigUint::zero()
107 }
108
109 fn b_int() -> BigUint {
110 BigUint::from(4u32)
111 }
112}
113
114pub fn bls12381_decompress<E: EllipticCurve>(bytes_be: &[u8], sign_bit: u32) -> AffinePoint<E> {
115 let mut g1_bytes_be: [u8; 48] = bytes_be.try_into().unwrap();
116 let mut flags = COMPRESSION_FLAG;
117 if sign_bit == 1 {
118 flags |= Y_IS_ODD_FLAG;
119 };
120
121 g1_bytes_be[0] |= flags;
123 let point = deserialize_g1(&g1_bytes_be).unwrap();
124
125 let x_str = point.getx().to_string();
126 let x = BigUint::from_str_radix(x_str.as_str(), 16).unwrap();
127 let y_str = point.gety().to_string();
128 let y = BigUint::from_str_radix(y_str.as_str(), 16).unwrap();
129
130 AffinePoint::new(x, y)
131}
132
133pub fn bls12381_sqrt(a: &BigUint) -> BigUint {
134 let a_big = Big::from_bytes(a.to_bytes_be().as_slice());
135
136 let a_sqrt = FP::new_big(a_big).sqrt();
137
138 BigUint::from_str_radix(a_sqrt.to_string().as_str(), 16).unwrap()
139}
140
141#[cfg(test)]
142mod tests {
143
144 use amcl::bls381::bls381::proof_of_possession::G1_BYTES;
145
146 use super::*;
147 use crate::utils::biguint_from_limbs;
148 use num::bigint::RandBigInt;
149 use rand::thread_rng;
150
151 const NUM_TEST_CASES: usize = 10;
152
153 #[test]
154 fn test_weierstrass_biguint_scalar_mul() {
155 assert_eq!(biguint_from_limbs(Bls12381BaseField::MODULUS), Bls12381BaseField::modulus());
156 }
157
158 #[test]
159 fn test_bls12381_decompress() {
160 let mut point = {
164 let (x, y) = Bls12381Parameters::generator();
165 AffinePoint::<SwCurve<Bls12381Parameters>>::new(x, y)
166 };
167 for _ in 0..NUM_TEST_CASES {
168 let (compressed_point, is_odd) = {
169 let mut result = [0u8; G1_BYTES];
170 let x = point.x.to_bytes_le();
171 result[..x.len()].copy_from_slice(&x);
172 result.reverse();
173
174 let y = point.y.clone();
176 let y_neg = Bls12381BaseField::modulus() - y.clone();
177
178 let mut is_odd = 0;
180 if y > y_neg {
181 result[0] += Y_IS_ODD_FLAG;
182 is_odd = 1;
183 }
184 result[0] += COMPRESSION_FLAG;
185
186 (result, is_odd)
187 };
188 assert_eq!(point, bls12381_decompress(&compressed_point, is_odd));
189
190 point = point.clone().sw_double();
192 }
193 }
194
195 #[test]
196 fn test_bls12381_sqrt() {
197 let mut rng = thread_rng();
198 for _ in 0..NUM_TEST_CASES {
199 let x = rng.gen_biguint(256) % Bls12381BaseField::modulus();
202 let x_2 = (&x * &x) % Bls12381BaseField::modulus();
203 let sqrt = bls12381_sqrt(&x_2);
204 let sqrt_2 = (&sqrt * &sqrt) % Bls12381BaseField::modulus();
205 assert_eq!(sqrt_2, x_2);
206 }
207 }
208
209 #[test]
210 fn test_bls12381_params() {
211 use crate::params::FieldParameters;
212
213 assert_eq!(
214 Bls12381BaseField::modulus(),
215 BigUint::from_bytes_le(<Bls12381BaseField as FieldParameters>::MODULUS)
216 );
217 }
218}