Skip to main content

airbender_crypto/bls12_381/
eip2537.rs

1// EIP-2537 serialization helpers
2// These are defined in the crypto crate to avoid ICE when compiling for RISC-V
3// The issue is that functions in external crates that use Fq/G1/G2 types trigger
4// compiler bugs during predicate checking for generic constants.
5
6use super::{Fq, Fq2, G1Affine, G2Affine};
7use crate::ark_ec::AffineRepr;
8use crate::ark_ff::PrimeField;
9
10const FIELD_ELEMENT_LEN: usize = 64;
11const G1_LEN: usize = 128;
12const G2_LEN: usize = 256;
13
14#[inline(never)]
15pub fn parse_fq_bytes(input: &[u8; FIELD_ELEMENT_LEN]) -> Option<Fq> {
16    if input[..16].iter().all(|el| *el == 0) == false {
17        return None;
18    }
19    let mut repr = <Fq as PrimeField>::BigInt::zero();
20    let repr_slice = repr.as_mut();
21    for (dst, src) in repr_slice.iter_mut().zip(input[16..].chunks_exact(8).rev()) {
22        *dst = u64::from_be_bytes(src.try_into().unwrap());
23    }
24    Fq::from_bigint(repr)
25}
26
27#[inline(never)]
28pub fn parse_fq2_bytes(input: &[u8; FIELD_ELEMENT_LEN * 2]) -> Option<Fq2> {
29    let c0 = parse_fq_bytes(input[0..64].try_into().ok()?)?;
30    let c1 = parse_fq_bytes(input[64..128].try_into().ok()?)?;
31    Some(Fq2 { c0, c1 })
32}
33
34#[inline(never)]
35pub fn parse_g1_bytes(input: &[u8; G1_LEN]) -> Option<(G1Affine, bool)> {
36    if input.iter().all(|el| *el == 0) {
37        return Some((G1Affine::identity(), false));
38    }
39    let x = parse_fq_bytes(input[0..64].try_into().ok()?)?;
40    let y = parse_fq_bytes(input[64..128].try_into().ok()?)?;
41    let point = G1Affine::new_unchecked(x, y);
42
43    if !point.is_on_curve() {
44        return None;
45    }
46
47    Some((point, true))
48}
49
50#[inline(never)]
51pub fn parse_g2_bytes(input: &[u8; G2_LEN]) -> Option<(G2Affine, bool)> {
52    if input.iter().all(|el| *el == 0) {
53        return Some((G2Affine::identity(), false));
54    }
55    let x = parse_fq2_bytes(input[0..128].try_into().ok()?)?;
56    let y = parse_fq2_bytes(input[128..256].try_into().ok()?)?;
57    let point = G2Affine::new_unchecked(x, y);
58
59    if !point.is_on_curve() {
60        return None;
61    }
62
63    Some((point, true))
64}
65
66#[inline(never)]
67pub fn serialize_fq_bytes(el: Fq, output: &mut [u8; FIELD_ELEMENT_LEN]) {
68    output[..16].fill(0);
69    let bigint = el.into_bigint();
70    let words = bigint.as_ref();
71    for (i, word) in words.iter().take(6).enumerate() {
72        let bytes = word.to_be_bytes();
73        let start = 16 + (5 - i) * 8;
74        output[start..start + 8].copy_from_slice(&bytes);
75    }
76}
77
78#[inline(never)]
79pub fn serialize_fq2_bytes(el: Fq2, output: &mut [u8; FIELD_ELEMENT_LEN * 2]) {
80    let (left, right) = output.split_at_mut(64);
81    serialize_fq_bytes(el.c0, left.try_into().unwrap());
82    serialize_fq_bytes(el.c1, right.try_into().unwrap());
83}
84
85#[inline(never)]
86pub fn serialize_g1_bytes(el: G1Affine, output: &mut [u8; G1_LEN]) {
87    if let Some((x, y)) = el.xy() {
88        let (left, right) = output.split_at_mut(64);
89        serialize_fq_bytes(x, left.try_into().unwrap());
90        serialize_fq_bytes(y, right.try_into().unwrap());
91    } else {
92        output.fill(0);
93    }
94}
95
96#[inline(never)]
97pub fn serialize_g2_bytes(el: G2Affine, output: &mut [u8; G2_LEN]) {
98    if let Some((x, y)) = el.xy() {
99        let (left, right) = output.split_at_mut(128);
100        serialize_fq2_bytes(x, left.try_into().unwrap());
101        serialize_fq2_bytes(y, right.try_into().unwrap());
102    } else {
103        output.fill(0);
104    }
105}