1use crate::secret_key::is_all_zero;
2use crate::{DerivableKey, Error, Result};
3
4use blst::*;
5use chik_sha2::Sha256;
6use chik_traits::{read_bytes, Streamable};
7#[cfg(feature = "py-bindings")]
8use pyo3::exceptions::PyNotImplementedError;
9#[cfg(feature = "py-bindings")]
10use pyo3::prelude::*;
11#[cfg(feature = "py-bindings")]
12use pyo3::types::PyType;
13use std::fmt;
14use std::hash::{Hash, Hasher};
15use std::io::Cursor;
16use std::mem::MaybeUninit;
17use std::ops::{Add, AddAssign, Neg, SubAssign};
18
19#[cfg_attr(
20 feature = "py-bindings",
21 pyo3::pyclass(name = "G1Element"),
22 derive(chik_py_streamable_macro::PyStreamable)
23)]
24#[derive(Clone, Copy, Default)]
25pub struct PublicKey(pub(crate) blst_p1);
26
27#[cfg(feature = "arbitrary")]
28impl<'a> arbitrary::Arbitrary<'a> for PublicKey {
29 fn arbitrary(_u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
30 Ok(Self::default())
32 }
33}
34
35impl PublicKey {
36 pub fn from_bytes_unchecked(bytes: &[u8; 48]) -> Result<Self> {
37 let zeros_only = is_all_zero(&bytes[1..]);
40
41 if (bytes[0] & 0xc0) == 0xc0 {
42 if bytes[0] != 0xc0 || !zeros_only {
44 return Err(Error::G1NotCanonical);
45 }
46 return Ok(Self::default());
48 }
49
50 if (bytes[0] & 0xc0) != 0x80 {
51 return Err(Error::G1InfinityInvalidBits);
52 }
53 if zeros_only {
54 return Err(Error::G1InfinityNotZero);
55 }
56
57 let p1 = unsafe {
58 let mut p1_affine = MaybeUninit::<blst_p1_affine>::uninit();
59 let ret = blst_p1_uncompress(p1_affine.as_mut_ptr(), bytes.as_ptr());
60 if ret != BLST_ERROR::BLST_SUCCESS {
61 return Err(Error::InvalidPublicKey(ret));
62 }
63 let mut p1 = MaybeUninit::<blst_p1>::uninit();
64 blst_p1_from_affine(p1.as_mut_ptr(), &p1_affine.assume_init());
65 p1.assume_init()
66 };
67 Ok(Self(p1))
68 }
69
70 pub fn generator() -> Self {
71 let p1 = unsafe { *blst_p1_generator() };
72 Self(p1)
73 }
74
75 pub fn from_integer(int_bytes: &[u8]) -> Self {
79 let p1 = unsafe {
80 let mut scalar = MaybeUninit::<blst_scalar>::uninit();
81 blst_scalar_from_be_bytes(scalar.as_mut_ptr(), int_bytes.as_ptr(), int_bytes.len());
82 let mut p1 = MaybeUninit::<blst_p1>::uninit();
83 blst_p1_mult(
84 p1.as_mut_ptr(),
85 blst_p1_generator(),
86 scalar.as_ptr().cast::<u8>(),
87 256,
88 );
89 p1.assume_init()
90 };
91 Self(p1)
92 }
93
94 pub fn from_bytes(bytes: &[u8; 48]) -> Result<Self> {
95 let ret = Self::from_bytes_unchecked(bytes)?;
96 if ret.is_valid() {
97 Ok(ret)
98 } else {
99 Err(Error::InvalidPublicKey(BLST_ERROR::BLST_POINT_NOT_ON_CURVE))
100 }
101 }
102
103 pub fn from_uncompressed(buf: &[u8; 96]) -> Result<Self> {
104 let p1 = unsafe {
105 let mut p1_affine = MaybeUninit::<blst_p1_affine>::uninit();
106 let ret = blst_p1_deserialize(p1_affine.as_mut_ptr(), buf.as_ptr());
107 if ret != BLST_ERROR::BLST_SUCCESS {
108 return Err(Error::InvalidSignature(ret));
109 }
110 let mut p1 = MaybeUninit::<blst_p1>::uninit();
111 blst_p1_from_affine(p1.as_mut_ptr(), &p1_affine.assume_init());
112 p1.assume_init()
113 };
114 Ok(Self(p1))
115 }
116
117 pub fn to_bytes(&self) -> [u8; 48] {
118 unsafe {
119 let mut bytes = MaybeUninit::<[u8; 48]>::uninit();
120 blst_p1_compress(bytes.as_mut_ptr().cast::<u8>(), &self.0);
121 bytes.assume_init()
122 }
123 }
124
125 pub fn is_valid(&self) -> bool {
126 unsafe { blst_p1_is_inf(&self.0) || blst_p1_in_g1(&self.0) }
129 }
130
131 pub fn is_inf(&self) -> bool {
132 unsafe { blst_p1_is_inf(&self.0) }
133 }
134
135 pub fn negate(&mut self) {
136 unsafe {
137 blst_p1_cneg(&mut self.0, true);
138 }
139 }
140
141 pub fn scalar_multiply(&mut self, int_bytes: &[u8]) {
142 unsafe {
143 let mut scalar = MaybeUninit::<blst_scalar>::uninit();
144 blst_scalar_from_be_bytes(scalar.as_mut_ptr(), int_bytes.as_ptr(), int_bytes.len());
145 blst_p1_mult(&mut self.0, &self.0, scalar.as_ptr().cast::<u8>(), 256);
146 }
147 }
148
149 pub fn get_fingerprint(&self) -> u32 {
150 let mut hasher = Sha256::new();
151 hasher.update(self.to_bytes());
152 let hash: [u8; 32] = hasher.finalize();
153 u32::from_be_bytes(hash[0..4].try_into().unwrap())
154 }
155}
156
157impl PartialEq for PublicKey {
158 fn eq(&self, other: &Self) -> bool {
159 unsafe { blst_p1_is_equal(&self.0, &other.0) }
160 }
161}
162impl Eq for PublicKey {}
163
164#[cfg(feature = "serde")]
165impl serde::Serialize for PublicKey {
166 fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
167 where
168 S: serde::Serializer,
169 {
170 chik_serde::ser_bytes(&self.to_bytes(), serializer, true)
171 }
172}
173
174#[cfg(feature = "serde")]
175impl<'de> serde::Deserialize<'de> for PublicKey {
176 fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
177 where
178 D: serde::Deserializer<'de>,
179 {
180 Self::from_bytes(&chik_serde::de_bytes(deserializer)?).map_err(serde::de::Error::custom)
181 }
182}
183
184impl Streamable for PublicKey {
185 fn update_digest(&self, digest: &mut Sha256) {
186 digest.update(self.to_bytes());
187 }
188
189 fn stream(&self, out: &mut Vec<u8>) -> chik_traits::Result<()> {
190 out.extend_from_slice(&self.to_bytes());
191 Ok(())
192 }
193
194 fn parse<const TRUSTED: bool>(input: &mut Cursor<&[u8]>) -> chik_traits::Result<Self> {
195 let input = read_bytes(input, 48)?.try_into().unwrap();
196 if TRUSTED {
197 Ok(Self::from_bytes_unchecked(input)?)
198 } else {
199 Ok(Self::from_bytes(input)?)
200 }
201 }
202}
203
204impl Hash for PublicKey {
205 fn hash<H: Hasher>(&self, state: &mut H) {
206 state.write(&self.to_bytes());
207 }
208}
209
210impl Neg for PublicKey {
211 type Output = PublicKey;
212 fn neg(mut self) -> Self::Output {
213 self.negate();
214 self
215 }
216}
217
218impl Neg for &PublicKey {
219 type Output = PublicKey;
220 fn neg(self) -> Self::Output {
221 let mut ret = *self;
222 ret.negate();
223 ret
224 }
225}
226
227impl AddAssign<&PublicKey> for PublicKey {
228 fn add_assign(&mut self, rhs: &PublicKey) {
229 unsafe {
230 blst_p1_add_or_double(&mut self.0, &self.0, &rhs.0);
231 }
232 }
233}
234
235impl SubAssign<&PublicKey> for PublicKey {
236 fn sub_assign(&mut self, rhs: &PublicKey) {
237 unsafe {
238 let mut neg = *rhs;
239 blst_p1_cneg(&mut neg.0, true);
240 blst_p1_add_or_double(&mut self.0, &self.0, &neg.0);
241 }
242 }
243}
244
245impl Add<&PublicKey> for &PublicKey {
246 type Output = PublicKey;
247 fn add(self, rhs: &PublicKey) -> PublicKey {
248 let p1 = unsafe {
249 let mut ret = MaybeUninit::<blst_p1>::uninit();
250 blst_p1_add_or_double(ret.as_mut_ptr(), &self.0, &rhs.0);
251 ret.assume_init()
252 };
253 PublicKey(p1)
254 }
255}
256
257impl Add<&PublicKey> for PublicKey {
258 type Output = PublicKey;
259 fn add(mut self, rhs: &PublicKey) -> PublicKey {
260 unsafe {
261 blst_p1_add_or_double(&mut self.0, &self.0, &rhs.0);
262 self
263 }
264 }
265}
266
267impl fmt::Debug for PublicKey {
268 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
269 formatter.write_fmt(format_args!(
270 "<G1Element {}>",
271 &hex::encode(self.to_bytes())
272 ))
273 }
274}
275
276impl DerivableKey for PublicKey {
277 fn derive_unhardened(&self, idx: u32) -> Self {
278 let mut hasher = Sha256::new();
279 hasher.update(self.to_bytes());
280 hasher.update(idx.to_be_bytes());
281 let digest: [u8; 32] = hasher.finalize();
282
283 let p1 = unsafe {
284 let mut nonce = MaybeUninit::<blst_scalar>::uninit();
285 blst_scalar_from_lendian(nonce.as_mut_ptr(), digest.as_ptr());
286 let mut bte = MaybeUninit::<[u8; 48]>::uninit();
287 blst_bendian_from_scalar(bte.as_mut_ptr().cast::<u8>(), nonce.as_ptr());
288 let mut p1 = MaybeUninit::<blst_p1>::uninit();
289 blst_p1_mult(
290 p1.as_mut_ptr(),
291 blst_p1_generator(),
292 bte.as_ptr().cast::<u8>(),
293 256,
294 );
295 blst_p1_add(p1.as_mut_ptr(), p1.as_mut_ptr(), &self.0);
296 p1.assume_init()
297 };
298 PublicKey(p1)
299 }
300}
301
302pub(crate) const DST: &[u8] = b"BLS_SIG_BLS12381G1_XMD:SHA-256_SSWU_RO_AUG_";
303
304pub fn hash_to_g1(msg: &[u8]) -> PublicKey {
305 hash_to_g1_with_dst(msg, DST)
306}
307
308pub fn hash_to_g1_with_dst(msg: &[u8], dst: &[u8]) -> PublicKey {
309 let p1 = unsafe {
310 let mut p1 = MaybeUninit::<blst_p1>::uninit();
311 blst_hash_to_g1(
312 p1.as_mut_ptr(),
313 msg.as_ptr(),
314 msg.len(),
315 dst.as_ptr(),
316 dst.len(),
317 std::ptr::null(),
318 0,
319 );
320 p1.assume_init()
321 };
322 PublicKey(p1)
323}
324
325#[cfg(feature = "py-bindings")]
326#[pyo3::pymethods]
327impl PublicKey {
328 #[classattr]
329 pub const SIZE: usize = 48;
330
331 #[new]
332 pub fn init() -> Self {
333 Self::default()
334 }
335
336 #[staticmethod]
337 #[pyo3(name = "generator")]
338 pub fn py_generator() -> Self {
339 Self::generator()
340 }
341
342 pub fn verify(&self, signature: &crate::Signature, msg: &[u8]) -> bool {
343 crate::verify(signature, self, msg)
344 }
345
346 pub fn pair(&self, other: &crate::Signature) -> crate::GTElement {
347 other.pair(self)
348 }
349
350 #[classmethod]
351 #[pyo3(name = "from_parent")]
352 pub fn from_parent(_cls: &Bound<'_, PyType>, _instance: &Self) -> PyResult<PyObject> {
353 Err(PyNotImplementedError::new_err(
354 "PublicKey does not support from_parent().",
355 ))
356 }
357
358 #[pyo3(name = "get_fingerprint")]
359 pub fn py_get_fingerprint(&self) -> u32 {
360 self.get_fingerprint()
361 }
362
363 #[pyo3(name = "derive_unhardened")]
364 #[must_use]
365 pub fn py_derive_unhardened(&self, idx: u32) -> Self {
366 self.derive_unhardened(idx)
367 }
368
369 pub fn __str__(&self) -> String {
370 hex::encode(self.to_bytes())
371 }
372
373 #[must_use]
374 pub fn __add__(&self, rhs: &Self) -> Self {
375 self + rhs
376 }
377
378 pub fn __iadd__(&mut self, rhs: &Self) {
379 *self += rhs;
380 }
381}
382
383#[cfg(feature = "py-bindings")]
384mod pybindings {
385 use super::*;
386
387 use crate::parse_hex::parse_hex_string;
388
389 use chik_traits::{FromJsonDict, ToJsonDict};
390
391 impl ToJsonDict for PublicKey {
392 fn to_json_dict(&self, py: Python<'_>) -> PyResult<PyObject> {
393 let bytes = self.to_bytes();
394 Ok(("0x".to_string() + &hex::encode(bytes))
395 .into_pyobject(py)?
396 .into_any()
397 .unbind())
398 }
399 }
400
401 impl FromJsonDict for PublicKey {
402 fn from_json_dict(o: &Bound<'_, PyAny>) -> PyResult<Self> {
403 Ok(Self::from_bytes(
404 parse_hex_string(o, 48, "PublicKey")?
405 .as_slice()
406 .try_into()
407 .unwrap(),
408 )?)
409 }
410 }
411}
412
413#[cfg(test)]
414mod tests {
415 use super::*;
416 use crate::SecretKey;
417 use hex::FromHex;
418 use rand::rngs::StdRng;
419 use rand::{Rng, SeedableRng};
420 use rstest::rstest;
421
422 #[test]
423 fn test_derive_unhardened() {
424 let sk_hex = "52d75c4707e39595b27314547f9723e5530c01198af3fc5849d9a7af65631efb";
425 let sk = SecretKey::from_bytes(&<[u8; 32]>::from_hex(sk_hex).unwrap()).unwrap();
426 let pk = sk.public_key();
427
428 for idx in 0..4_usize {
431 let derived_sk = sk.derive_unhardened(idx as u32);
432 let derived_pk = pk.derive_unhardened(idx as u32);
433 assert_eq!(derived_pk.to_bytes(), derived_sk.public_key().to_bytes());
434 }
435 }
436
437 #[test]
438 fn test_from_bytes() {
439 let mut rng = StdRng::seed_from_u64(1337);
440 let mut data = [0u8; 48];
441 for _i in 0..50 {
442 rng.fill(data.as_mut_slice());
443 data[0] = 0x80;
445 match PublicKey::from_bytes(&data) {
447 Err(Error::InvalidPublicKey(err)) => {
448 assert!([
449 BLST_ERROR::BLST_BAD_ENCODING,
450 BLST_ERROR::BLST_POINT_NOT_ON_CURVE
451 ]
452 .contains(&err));
453 }
454 Err(e) => {
455 panic!("unexpected error from_bytes(): {e}");
456 }
457 Ok(v) => {
458 panic!("unexpected value from_bytes(): {v:?}");
459 }
460 }
461 }
462 }
463
464 #[rstest]
465 #[case("c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001", Error::G1NotCanonical)]
466 #[case("c08000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", Error::G1NotCanonical)]
467 #[case("c80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", Error::G1NotCanonical)]
468 #[case("e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", Error::G1NotCanonical)]
469 #[case("d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", Error::G1NotCanonical)]
470 #[case("800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", Error::G1InfinityNotZero)]
471 #[case("400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", Error::G1InfinityInvalidBits)]
472 fn test_from_bytes_failures(#[case] input: &str, #[case()] error: Error) {
473 let bytes: [u8; 48] = hex::decode(input).unwrap().try_into().unwrap();
474 assert_eq!(PublicKey::from_bytes(&bytes).unwrap_err(), error);
475 }
476
477 #[test]
478 fn test_from_bytes_infinity() {
479 let bytes: [u8; 48] = hex::decode("c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000").unwrap().try_into().unwrap();
480 let pk = PublicKey::from_bytes(&bytes).unwrap();
481 assert_eq!(pk, PublicKey::default());
482 }
483
484 #[test]
485 fn test_get_fingerprint() {
486 let bytes: [u8; 48] = hex::decode("997cc43ed8788f841fcf3071f6f212b89ba494b6ebaf1bda88c3f9de9d968a61f3b7284a5ee13889399ca71a026549a2")
487 .unwrap()
488 .as_slice()
489 .try_into()
490 .unwrap();
491 let pk = PublicKey::from_bytes(&bytes).unwrap();
492 assert_eq!(pk.get_fingerprint(), 651_010_559);
493 }
494
495 #[test]
496 fn test_aggregate_pubkey() {
497 let sk_hex = "52d75c4707e39595b27314547f9723e5530c01198af3fc5849d9a7af65631efb";
507 let sk = SecretKey::from_bytes(&<[u8; 32]>::from_hex(sk_hex).unwrap()).unwrap();
508 let pk = sk.public_key();
509 let pk2 = &pk + &pk;
510 let pk3 = &pk + &pk + &pk;
511
512 assert_eq!(pk2, PublicKey::from_bytes(&<[u8; 48]>::from_hex("b1b8033286299e7f238aede0d3fea48d133a1e233139085f72c102c2e6cc1f8a4ea64ed2838c10bbd2ef8f78ef271bf3").unwrap()).unwrap());
513 assert_eq!(pk3, PublicKey::from_bytes(&<[u8; 48]>::from_hex("a8bc2047d90c04a12e8c38050ec0feb4417b4d5689165cd2cea8a7903aad1778e36548a46d427b5ec571364515e456d6").unwrap()).unwrap());
514 }
515
516 #[test]
517 fn test_roundtrip() {
518 let mut rng = StdRng::seed_from_u64(1337);
519 let mut data = [0u8; 32];
520 for _i in 0..50 {
521 rng.fill(data.as_mut_slice());
522 let sk = SecretKey::from_seed(&data);
523 let pk = sk.public_key();
524 let bytes = pk.to_bytes();
525 let pk2 = PublicKey::from_bytes(&bytes).unwrap();
526 assert_eq!(pk, pk2);
527 }
528 }
529
530 #[test]
531 fn test_default_is_valid() {
532 let pk = PublicKey::default();
533 assert!(pk.is_valid());
534 }
535
536 #[test]
537 fn test_infinity_is_valid() {
538 let mut data = [0u8; 48];
539 data[0] = 0xc0;
540 let pk = PublicKey::from_bytes(&data).unwrap();
541 assert!(pk.is_valid());
542 }
543
544 #[test]
545 fn test_is_valid() {
546 let mut rng = StdRng::seed_from_u64(1337);
547 let mut data = [0u8; 32];
548 for _i in 0..50 {
549 rng.fill(data.as_mut_slice());
550 let sk = SecretKey::from_seed(&data);
551 let pk = sk.public_key();
552 assert!(pk.is_valid());
553 }
554 }
555
556 #[test]
557 fn test_default_is_inf() {
558 let pk = PublicKey::default();
559 assert!(pk.is_inf());
560 }
561
562 #[test]
563 fn test_infinity() {
564 let mut data = [0u8; 48];
565 data[0] = 0xc0;
566 let pk = PublicKey::from_bytes(&data).unwrap();
567 assert!(pk.is_inf());
568 }
569
570 #[test]
571 fn test_is_inf() {
572 let mut rng = StdRng::seed_from_u64(1337);
573 let mut data = [0u8; 32];
574 for _i in 0..500 {
575 rng.fill(data.as_mut_slice());
576 let sk = SecretKey::from_seed(&data);
577 let pk = sk.public_key();
578 assert!(!pk.is_inf());
579 }
580 }
581
582 #[test]
583 fn test_hash() {
584 fn hash<T: Hash>(v: T) -> u64 {
585 use std::collections::hash_map::DefaultHasher;
586 let mut h = DefaultHasher::new();
587 v.hash(&mut h);
588 h.finish()
589 }
590
591 let mut rng = StdRng::seed_from_u64(1337);
592 let mut data = [0u8; 32];
593 rng.fill(data.as_mut_slice());
594
595 let sk = SecretKey::from_seed(&data);
596 let pk1 = sk.public_key();
597 let pk2 = pk1.derive_unhardened(1);
598 let pk3 = pk1.derive_unhardened(2);
599
600 assert!(hash(pk2) != hash(pk3));
601 assert!(hash(pk1.derive_unhardened(42)) == hash(pk1.derive_unhardened(42)));
602 }
603
604 #[test]
605 fn test_debug() {
606 let mut data = [0u8; 48];
607 data[0] = 0xc0;
608 let pk = PublicKey::from_bytes(&data).unwrap();
609 assert_eq!(
610 format!("{pk:?}"),
611 format!("<G1Element {}>", hex::encode(data))
612 );
613 }
614
615 #[test]
616 fn test_generator() {
617 assert_eq!(
618 hex::encode(PublicKey::generator().to_bytes()),
619 "97f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb"
620 );
621 }
622
623 #[test]
624 fn test_from_integer() {
625 let mut rng = StdRng::seed_from_u64(1337);
626 let mut data = [0u8; 32];
627 for _i in 0..50 {
628 rng.fill(&mut data[1..]);
631
632 let g1 = PublicKey::from_integer(&data);
633 let expected_g1 = SecretKey::from_bytes(&data)
634 .expect("invalid public key")
635 .public_key();
636 assert_eq!(g1, expected_g1);
637 }
638 }
639
640 #[rstest]
642 #[case("06f6ba2972ab1c83718d747b2d55cca96d08729b1ea5a3ab3479b8efe2d455885abf65f58d1507d7f260cd2a4687db821171c9d8dc5c0f5c3c4fd64b26cf93ff28b2e683c409fb374c4e26cc548c6f7cef891e60b55e6115bb38bbe97822e4d4", "a6f6ba2972ab1c83718d747b2d55cca96d08729b1ea5a3ab3479b8efe2d455885abf65f58d1507d7f260cd2a4687db82")]
643 #[case("127271e81a1cb5c08a68694fcd5bd52f475d545edd4fbd49b9f6ec402ee1973f9f4102bf3bfccdcbf1b2f862af89a1340d40795c1c09d1e10b1acfa0f3a97a71bf29c11665743fa8d30e57e450b8762959571d6f6d253b236931b93cf634e7cf", "b27271e81a1cb5c08a68694fcd5bd52f475d545edd4fbd49b9f6ec402ee1973f9f4102bf3bfccdcbf1b2f862af89a134")]
644 #[case("0fe94ac2d68d39d9207ea0cae4bb2177f7352bd754173ed27bd13b4c156f77f8885458886ee9fbd212719f27a96397c110fa7b4f898b1c45c2e82c5d46b52bdad95cae8299d4fd4556ae02baf20a5ec989fc62f28c8b6b3df6dc696f2afb6e20", "afe94ac2d68d39d9207ea0cae4bb2177f7352bd754173ed27bd13b4c156f77f8885458886ee9fbd212719f27a96397c1")]
645 #[case("13aedc305adfdbc854aa105c41085618484858e6baa276b176fd89415021f7a0c75ff4f9ec39f482f142f1b54c11144815e519df6f71b1db46c83b1d2bdf381fc974059f3ccd87ed5259221dc37c50c3be407b58990d14b6d5bb79dad9ab8c42", "b3aedc305adfdbc854aa105c41085618484858e6baa276b176fd89415021f7a0c75ff4f9ec39f482f142f1b54c111448")]
646 fn test_from_uncompressed(#[case] input: &str, #[case] expect: &str) {
647 let input = hex::decode(input).unwrap();
648 let g1 = PublicKey::from_uncompressed(input.as_slice().try_into().unwrap()).unwrap();
649 let compressed = g1.to_bytes();
650 assert_eq!(hex::encode(compressed), expect);
651 }
652
653 #[test]
654 fn test_negate_roundtrip() {
655 let mut rng = StdRng::seed_from_u64(1337);
656 let mut data = [0u8; 32];
657 for _i in 0..50 {
658 rng.fill(&mut data[1..]);
661
662 let g1 = PublicKey::from_integer(&data);
663 let mut g1_neg = g1;
664 g1_neg.negate();
665 assert!(g1_neg != g1);
666
667 g1_neg.negate();
668 assert!(g1_neg == g1);
669 }
670 }
671
672 #[test]
673 fn test_negate_infinity() {
674 let g1 = PublicKey::default();
675 let mut g1_neg = g1;
676 g1_neg.negate();
678 assert!(g1_neg == g1);
679 }
680
681 #[test]
682 fn test_negate() {
683 let mut rng = StdRng::seed_from_u64(1337);
684 let mut data = [0u8; 32];
685 for _i in 0..50 {
686 rng.fill(&mut data[1..]);
689
690 let g1 = PublicKey::from_integer(&data);
691 let mut g1_neg = g1;
692 g1_neg.negate();
693
694 let mut g1_double = g1;
695 g1_double += &g1;
697 assert!(g1_double != g1);
698 g1_double += &g1_neg;
699 assert!(g1_double == g1);
700 }
701 }
702
703 #[test]
704 fn test_scalar_multiply() {
705 let mut rng = StdRng::seed_from_u64(1337);
706 let mut data = [0u8; 32];
707 for _i in 0..50 {
708 rng.fill(&mut data[1..]);
711
712 let mut g1 = PublicKey::from_integer(&data);
713 let mut g1_double = g1;
714 g1_double += &g1;
715 assert!(g1_double != g1);
716 g1.scalar_multiply(&[2]);
718 assert!(g1_double == g1);
719 }
720 }
721
722 #[test]
723 fn test_hash_to_g1_different_dst() {
724 const DEFAULT_DST: &[u8] = b"BLS_SIG_BLS12381G1_XMD:SHA-256_SSWU_RO_AUG_";
725 const CUSTOM_DST: &[u8] = b"foobar";
726
727 let mut rng = StdRng::seed_from_u64(1337);
728 let mut msg = [0u8; 32];
729 for _i in 0..50 {
730 rng.fill(&mut msg);
731 let default_hash = hash_to_g1(&msg);
732 assert_eq!(default_hash, hash_to_g1_with_dst(&msg, DEFAULT_DST));
733 assert!(default_hash != hash_to_g1_with_dst(&msg, CUSTOM_DST));
734 }
735 }
736
737 #[rstest]
739 #[case("abcdef0123456789", "88e7302bf1fa8fcdecfb96f6b81475c3564d3bcaf552ccb338b1c48b9ba18ab7195c5067fe94fb216478188c0a3bef4a")]
740 fn test_hash_to_g1(#[case] input: &str, #[case] expect: &str) {
741 let g1 = hash_to_g1(input.as_bytes());
742 assert_eq!(hex::encode(g1.to_bytes()), expect);
743 }
744
745 #[rstest]
747 #[case("abcdef0123456789", "BLS_SIG_BLS12381G1_XMD:SHA-256_SSWU_RO_NUL_", "8dd8e3a9197ddefdc25dde980d219004d6aa130d1af9b1808f8b2b004ae94484ac62a08a739ec7843388019a79c437b0")]
748 #[case("abcdef0123456789", "BLS_SIG_BLS12381G1_XMD:SHA-256_SSWU_RO_AUG_", "88e7302bf1fa8fcdecfb96f6b81475c3564d3bcaf552ccb338b1c48b9ba18ab7195c5067fe94fb216478188c0a3bef4a")]
749 fn test_hash_to_g1_with_dst(#[case] input: &str, #[case] dst: &str, #[case] expect: &str) {
750 let g1 = hash_to_g1_with_dst(input.as_bytes(), dst.as_bytes());
751 assert_eq!(hex::encode(g1.to_bytes()), expect);
752 }
753}
754
755#[cfg(test)]
756#[cfg(feature = "py-bindings")]
757mod pytests {
758 use super::*;
759 use crate::SecretKey;
760 use pyo3::Python;
761 use rand::rngs::StdRng;
762 use rand::{Rng, SeedableRng};
763 use rstest::rstest;
764
765 #[test]
766 fn test_json_dict_roundtrip() {
767 pyo3::prepare_freethreaded_python();
768 let mut rng = StdRng::seed_from_u64(1337);
769 let mut data = [0u8; 32];
770 for _i in 0..50 {
771 rng.fill(data.as_mut_slice());
772 let sk = SecretKey::from_seed(&data);
773 let pk = sk.public_key();
774 Python::with_gil(|py| {
775 let string = pk.to_json_dict(py).expect("to_json_dict");
776 let py_class = py.get_type::<PublicKey>();
777 let pk2: PublicKey = PublicKey::from_json_dict(&py_class, py, string.bind(py))
778 .unwrap()
779 .extract(py)
780 .unwrap();
781 assert_eq!(pk, pk2);
782 });
783 }
784 }
785
786 #[rstest]
787 #[case("0x000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e", "PublicKey, invalid length 47 expected 48")]
788 #[case("0x000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f00", "PublicKey, invalid length 49 expected 48")]
789 #[case("000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e", "PublicKey, invalid length 47 expected 48")]
790 #[case("000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f00", "PublicKey, invalid length 49 expected 48")]
791 #[case("0x00r102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f", "invalid hex")]
792 fn test_json_dict(#[case] input: &str, #[case] msg: &str) {
793 pyo3::prepare_freethreaded_python();
794 Python::with_gil(|py| {
795 let py_class = py.get_type::<PublicKey>();
796 let err = PublicKey::from_json_dict(
797 &py_class,
798 py,
799 &input.to_string().into_pyobject(py).unwrap().into_any(),
800 )
801 .unwrap_err();
802 assert_eq!(err.value(py).to_string(), msg.to_string());
803 });
804 }
805}