commonware_cryptography/bls12381/primitives/
group.rsuse blst::{
blst_bendian_from_scalar, blst_final_exp, blst_fp12, blst_fr, blst_fr_add, blst_fr_from_scalar,
blst_fr_from_uint64, blst_fr_inverse, blst_fr_mul, blst_fr_sub, blst_hash_to_g1,
blst_hash_to_g2, blst_keygen_v3, blst_miller_loop, blst_p1, blst_p1_add_or_double,
blst_p1_affine, blst_p1_compress, blst_p1_from_affine, blst_p1_in_g1, blst_p1_is_inf,
blst_p1_mult, blst_p1_to_affine, blst_p1_uncompress, blst_p2, blst_p2_add_or_double,
blst_p2_affine, blst_p2_compress, blst_p2_from_affine, blst_p2_in_g2, blst_p2_is_inf,
blst_p2_mult, blst_p2_to_affine, blst_p2_uncompress, blst_scalar, blst_scalar_fr_check,
blst_scalar_from_bendian, blst_scalar_from_fr, BLS12_381_G1, BLS12_381_G2, BLST_ERROR,
};
use rand::RngCore;
use std::ptr;
use zeroize::Zeroize;
pub trait Element: Clone + Eq + PartialEq + Send + Sync {
fn zero() -> Self;
fn one() -> Self;
fn add(&mut self, rhs: &Self);
fn mul(&mut self, rhs: &Scalar);
fn serialize(&self) -> Vec<u8>;
fn size() -> usize;
fn deserialize(bytes: &[u8]) -> Option<Self>;
}
pub trait Point: Element {
fn map(&mut self, message: &[u8]);
}
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
#[repr(transparent)]
pub struct Scalar(blst_fr);
const SCALAR_LENGTH: usize = 32;
const BLST_FR_ONE: Scalar = Scalar(blst_fr {
l: [
0x0000_0001_ffff_fffe,
0x5884_b7fa_0003_4802,
0x998c_4fef_ecbc_4ff5,
0x1824_b159_acc5_056f,
],
});
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
#[repr(transparent)]
pub struct G1(blst_p1);
pub const G1_ELEMENT_BYTE_LENGTH: usize = 48;
pub const DST_G1: &[u8] = b"BLS_SIG_BLS12381G1_XMD:SHA-256_SSWU_RO_NUL_";
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
#[repr(transparent)]
pub struct G2(blst_p2);
pub const G2_ELEMENT_BYTE_LENGTH: usize = 96;
pub const DST_G2: &[u8] = b"BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_NUL_";
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub struct GT(blst_fp12);
pub type Private = Scalar;
pub const PRIVATE_KEY_LENGTH: usize = SCALAR_LENGTH;
pub type Public = G1;
pub type Signature = G2;
fn bits(scalar: &blst_scalar) -> usize {
let mut bits: usize = SCALAR_LENGTH * 8;
for i in scalar.b.iter().rev() {
let leading = i.leading_zeros();
bits -= leading as usize;
if leading < 8 {
break;
}
}
bits
}
#[derive(Clone, PartialEq, Copy)]
pub struct Share {
pub index: u32,
pub private: Private,
}
impl Share {
pub fn public(&self) -> Public {
let mut public = <Public as Element>::one();
public.mul(&self.private);
public
}
pub fn serialize(&self) -> Vec<u8> {
let mut bytes = [0u8; SCALAR_LENGTH + 4];
bytes[..4].copy_from_slice(&self.index.to_be_bytes());
bytes[4..].copy_from_slice(&self.private.serialize());
bytes.to_vec()
}
pub fn deserialize(bytes: &[u8]) -> Option<Self> {
if bytes.len() != SCALAR_LENGTH + 4 {
return None;
}
let index = u32::from_be_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]);
let private = Private::deserialize(&bytes[4..])?;
Some(Self { index, private })
}
}
impl Scalar {
pub fn rand<R: RngCore>(rng: &mut R) -> Self {
let mut ikm = [0u8; 64];
rng.fill_bytes(&mut ikm);
let mut ret = blst_fr::default();
unsafe {
let mut sc = blst_scalar::default();
blst_keygen_v3(&mut sc, ikm.as_ptr(), ikm.len(), ptr::null(), 0);
blst_fr_from_scalar(&mut ret, &sc);
}
Self(ret)
}
pub fn set_int(&mut self, i: u32) {
let buffer = [i as u64, 0, 0, 0];
unsafe { blst_fr_from_uint64(&mut self.0, buffer.as_ptr()) };
}
pub fn inverse(&self) -> Option<Self> {
if *self == Self::zero() {
return None;
}
let mut ret = blst_fr::default();
unsafe { blst_fr_inverse(&mut ret, &self.0) };
Some(Self(ret))
}
pub fn sub(&mut self, rhs: &Self) {
unsafe { blst_fr_sub(&mut self.0, &self.0, &rhs.0) }
}
}
impl Zeroize for Scalar {
fn zeroize(&mut self) {
self.0.l.zeroize();
}
}
impl Element for Scalar {
fn zero() -> Self {
Self(blst_fr::default())
}
fn one() -> Self {
BLST_FR_ONE
}
fn add(&mut self, rhs: &Self) {
unsafe {
blst_fr_add(&mut self.0, &self.0, &rhs.0);
}
}
fn mul(&mut self, rhs: &Self) {
unsafe {
blst_fr_mul(&mut self.0, &self.0, &rhs.0);
}
}
fn serialize(&self) -> Vec<u8> {
let mut bytes = [0u8; SCALAR_LENGTH];
unsafe {
let mut scalar = blst_scalar::default();
blst_scalar_from_fr(&mut scalar, &self.0);
blst_bendian_from_scalar(bytes.as_mut_ptr(), &scalar);
}
bytes.to_vec()
}
fn deserialize(bytes: &[u8]) -> Option<Self> {
if bytes.len() != SCALAR_LENGTH {
return None;
}
let mut ret = blst_fr::default();
unsafe {
let mut scalar = blst_scalar::default();
blst_scalar_from_bendian(&mut scalar, bytes.as_ptr());
if !blst_scalar_fr_check(&scalar) {
return None;
}
blst_fr_from_scalar(&mut ret, &scalar);
}
Some(Self(ret))
}
fn size() -> usize {
SCALAR_LENGTH
}
}
impl Element for G1 {
fn zero() -> Self {
Self(blst_p1::default())
}
fn one() -> Self {
let mut ret = blst_p1::default();
unsafe {
blst_p1_from_affine(&mut ret, &BLS12_381_G1);
}
Self(ret)
}
fn add(&mut self, rhs: &Self) {
unsafe {
blst_p1_add_or_double(&mut self.0, &self.0, &rhs.0);
}
}
fn mul(&mut self, rhs: &Scalar) {
let mut scalar: blst_scalar = blst_scalar::default();
unsafe {
blst_scalar_from_fr(&mut scalar, &rhs.0);
blst_p1_mult(&mut self.0, &self.0, scalar.b.as_ptr(), bits(&scalar));
}
}
fn serialize(&self) -> Vec<u8> {
let mut bytes = [0u8; G1_ELEMENT_BYTE_LENGTH];
unsafe {
blst_p1_compress(bytes.as_mut_ptr(), &self.0);
}
bytes.to_vec()
}
fn deserialize(bytes: &[u8]) -> Option<Self> {
if bytes.len() != G1_ELEMENT_BYTE_LENGTH {
return None;
}
let mut ret = blst_p1::default();
unsafe {
let mut affine = blst_p1_affine::default();
if blst_p1_uncompress(&mut affine, bytes.as_ptr()) != BLST_ERROR::BLST_SUCCESS {
return None;
}
blst_p1_from_affine(&mut ret, &affine);
if blst_p1_is_inf(&ret) {
return None;
}
if !blst_p1_in_g1(&ret) {
return None;
}
}
Some(Self(ret))
}
fn size() -> usize {
G1_ELEMENT_BYTE_LENGTH
}
}
impl Point for G1 {
fn map(&mut self, data: &[u8]) {
unsafe {
blst_hash_to_g1(
&mut self.0,
data.as_ptr(),
data.len(),
DST_G1.as_ptr(),
DST_G1.len(),
ptr::null(),
0,
);
}
}
}
impl Element for G2 {
fn zero() -> Self {
Self(blst_p2::default())
}
fn one() -> Self {
let mut ret = blst_p2::default();
unsafe {
blst_p2_from_affine(&mut ret, &BLS12_381_G2);
}
Self(ret)
}
fn add(&mut self, rhs: &Self) {
unsafe {
blst_p2_add_or_double(&mut self.0, &self.0, &rhs.0);
}
}
fn mul(&mut self, rhs: &Scalar) {
let mut scalar = blst_scalar::default();
unsafe {
blst_scalar_from_fr(&mut scalar, &rhs.0);
blst_p2_mult(&mut self.0, &self.0, scalar.b.as_ptr(), bits(&scalar));
}
}
fn serialize(&self) -> Vec<u8> {
let mut bytes = [0u8; G2_ELEMENT_BYTE_LENGTH];
unsafe {
blst_p2_compress(bytes.as_mut_ptr(), &self.0);
}
bytes.to_vec()
}
fn deserialize(bytes: &[u8]) -> Option<Self> {
if bytes.len() != G2_ELEMENT_BYTE_LENGTH {
return None;
}
let mut ret = blst_p2::default();
unsafe {
let mut affine = blst_p2_affine::default();
if blst_p2_uncompress(&mut affine, bytes.as_ptr()) != BLST_ERROR::BLST_SUCCESS {
return None;
}
blst_p2_from_affine(&mut ret, &affine);
if blst_p2_is_inf(&ret) {
return None;
}
if !blst_p2_in_g2(&ret) {
return None;
}
}
Some(Self(ret))
}
fn size() -> usize {
G2_ELEMENT_BYTE_LENGTH
}
}
impl Point for G2 {
fn map(&mut self, data: &[u8]) {
unsafe {
blst_hash_to_g2(
&mut self.0,
data.as_ptr(),
data.len(),
DST_G2.as_ptr(),
DST_G2.len(),
ptr::null(),
0,
);
}
}
}
fn pairing(p: &G1, q: &G2) -> GT {
let mut pa = blst_p1_affine::default();
let mut qa = blst_p2_affine::default();
let mut res = blst_fp12::default();
unsafe {
blst_p1_to_affine(&mut pa, &p.0);
blst_p2_to_affine(&mut qa, &q.0);
blst_miller_loop(&mut res, &qa, &pa);
blst_final_exp(&mut res, &res);
}
GT(res)
}
pub(super) fn equal(p: &G1, sig: &G2, hm: &G2) -> bool {
let left = pairing(&<G1 as Element>::one(), sig);
let right = pairing(p, hm);
left == right
}
#[cfg(test)]
mod tests {
use super::*;
use rand::prelude::*;
#[test]
fn basic_group() {
let s = Scalar::rand(&mut thread_rng());
let mut e1 = s;
let e2 = s;
let mut s2 = s;
s2.add(&s);
s2.mul(&s);
e1.add(&e2);
e1.mul(&e2);
let mut p1 = G1::zero();
p1.mul(&s2);
let mut p2 = G1::zero();
p2.mul(&s);
p2.add(&p2.clone());
assert_eq!(p1, p2);
}
}