Skip to main content

amaru_uplc/
bls.rs

1use bumpalo::collections::Vec as BumpVec;
2use once_cell::sync::Lazy;
3
4use crate::{arena::Arena, constant::Integer};
5
6pub static SCALAR_PERIOD: Lazy<Integer> = Lazy::new(|| {
7    let bytes: [u8; 32] = [
8        0x73, 0xed, 0xa7, 0x53, 0x29, 0x9d, 0x7d, 0x48, 0x33, 0x39, 0xd8, 0x08, 0x09, 0xa1, 0xd8,
9        0x05, 0x53, 0xbd, 0xa4, 0x02, 0xff, 0xfe, 0x5b, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
10        0x00, 0x01,
11    ];
12
13    Integer::from_bytes_be(num_bigint::Sign::Plus, &bytes)
14});
15
16pub const BLST_P1_COMPRESSED_SIZE: usize = 48;
17
18pub const BLST_P2_COMPRESSED_SIZE: usize = 96;
19
20pub const INTEGER_TO_BYTE_STRING_MAXIMUM_OUTPUT_LENGTH: i64 = 8192;
21
22#[derive(Debug, thiserror::Error)]
23#[error("BLS error: {0:?}")]
24pub struct BlsError(blst::BLST_ERROR);
25
26pub trait Compressable {
27    fn compress<'a>(&self, arena: &'a Arena) -> &'a [u8];
28
29    fn uncompress<'a>(arena: &'a Arena, bytes: &[u8]) -> Result<&'a Self, BlsError>
30    where
31        Self: std::marker::Sized;
32}
33
34impl Compressable for blst::blst_p1 {
35    fn compress<'a>(&self, arena: &'a Arena) -> &'a [u8] {
36        let mut out = [0u8; BLST_P1_COMPRESSED_SIZE];
37
38        unsafe {
39            blst::blst_p1_compress(&mut out as *mut _, self);
40        };
41
42        arena.alloc(BumpVec::from_iter_in(out, arena.as_bump()))
43    }
44
45    fn uncompress<'a>(arena: &'a Arena, bytes: &[u8]) -> Result<&'a Self, BlsError> {
46        if bytes.len() != BLST_P1_COMPRESSED_SIZE {
47            return Err(BlsError(blst::BLST_ERROR::BLST_BAD_ENCODING));
48        }
49
50        let mut affine = blst::blst_p1_affine::default();
51
52        let out = arena.alloc(blst::blst_p1::default());
53
54        unsafe {
55            let err = blst::blst_p1_uncompress(&mut affine as *mut _, bytes.as_ptr());
56
57            if err != blst::BLST_ERROR::BLST_SUCCESS {
58                return Err(BlsError(err));
59            }
60
61            blst::blst_p1_from_affine(out as *mut _, &affine);
62
63            let in_group = blst::blst_p1_in_g1(out);
64
65            if !in_group {
66                return Err(BlsError(blst::BLST_ERROR::BLST_POINT_NOT_IN_GROUP));
67            }
68        };
69
70        Ok(out)
71    }
72}
73
74impl Compressable for blst::blst_p2 {
75    fn compress<'a>(&self, arena: &'a Arena) -> &'a [u8] {
76        let mut out = [0; BLST_P2_COMPRESSED_SIZE];
77
78        unsafe {
79            blst::blst_p2_compress(&mut out as *mut _, self);
80        };
81
82        arena.alloc(BumpVec::from_iter_in(out, arena.as_bump()))
83    }
84
85    fn uncompress<'a>(arena: &'a Arena, bytes: &[u8]) -> Result<&'a Self, BlsError> {
86        if bytes.len() != BLST_P2_COMPRESSED_SIZE {
87            return Err(BlsError(blst::BLST_ERROR::BLST_BAD_ENCODING));
88        }
89
90        let mut affine = blst::blst_p2_affine::default();
91
92        let out = arena.alloc(blst::blst_p2::default());
93
94        unsafe {
95            let err = blst::blst_p2_uncompress(&mut affine as *mut _, bytes.as_ptr());
96
97            if err != blst::BLST_ERROR::BLST_SUCCESS {
98                return Err(BlsError(err));
99            }
100
101            blst::blst_p2_from_affine(out as *mut _, &affine);
102
103            let in_group = blst::blst_p2_in_g2(out);
104
105            if !in_group {
106                return Err(BlsError(blst::BLST_ERROR::BLST_POINT_NOT_IN_GROUP));
107            }
108        };
109
110        Ok(out)
111    }
112}