Skip to content

Commit

Permalink
feat: add hash-to-curve and small utils needed in bls-signatures
Browse files Browse the repository at this point in the history
  • Loading branch information
dignifiedquire authored Jan 24, 2021
1 parent 5803952 commit ea31380
Show file tree
Hide file tree
Showing 4 changed files with 215 additions and 7 deletions.
45 changes: 43 additions & 2 deletions src/g1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,18 @@ impl From<G1Projective> for G1Affine {
}
}

impl AsRef<blst_p1_affine> for G1Affine {
fn as_ref(&self) -> &blst_p1_affine {
&self.0
}
}

impl AsMut<blst_p1_affine> for G1Affine {
fn as_mut(&mut self) -> &mut blst_p1_affine {
&mut self.0
}
}

impl Eq for G1Affine {}
impl PartialEq for G1Affine {
#[inline]
Expand Down Expand Up @@ -208,7 +220,7 @@ impl G1Affine {
/// Attempts to deserialize an uncompressed element.
pub fn from_uncompressed(bytes: &[u8; 96]) -> Option<Self> {
G1Affine::from_uncompressed_unchecked(bytes).and_then(|el| {
if el.is_zero() || (el.is_torsion_free() && el.is_on_curve()) {
if el.is_zero() || el.is_torsion_free() {
Some(el)
} else {
None
Expand Down Expand Up @@ -236,7 +248,7 @@ impl G1Affine {
/// Attempts to deserialize a compressed element.
pub fn from_compressed(bytes: &[u8; 48]) -> Option<Self> {
G1Affine::from_compressed_unchecked(bytes).and_then(|el| {
if el.is_zero() || (el.is_torsion_free() && el.is_on_curve()) {
if el.is_zero() || el.is_torsion_free() {
Some(el)
} else {
None
Expand Down Expand Up @@ -377,6 +389,18 @@ impl fmt::Display for G1Projective {
}
}

impl AsRef<blst_p1> for G1Projective {
fn as_ref(&self) -> &blst_p1 {
&self.0
}
}

impl AsMut<blst_p1> for G1Projective {
fn as_mut(&mut self) -> &mut blst_p1 {
&mut self.0
}
}

impl From<&G1Affine> for G1Projective {
fn from(p: &G1Affine) -> G1Projective {
let mut out = blst_p1::default();
Expand Down Expand Up @@ -592,6 +616,23 @@ impl G1Projective {
pub fn z(&self) -> Fp {
Fp(self.0.z)
}

/// Hash to curve algorithm.
pub fn hash_to_curve(msg: &[u8], dst: &[u8], aug: &[u8]) -> Self {
let mut res = Self::zero();
unsafe {
blst_hash_to_g1(
&mut res.0,
msg.as_ptr(),
msg.len(),
dst.as_ptr(),
dst.len(),
aug.as_ptr(),
aug.len(),
);
}
res
}
}

impl groupy::CurveProjective for G1Projective {
Expand Down
49 changes: 44 additions & 5 deletions src/g2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use core::{

use blst::*;
use fff::{Field, PrimeField, PrimeFieldRepr};
use groupy::CurveProjective;
use rand_core::RngCore;

use crate::{Fp12, Fp2, G1Affine, Scalar, ScalarRepr};
Expand Down Expand Up @@ -39,6 +40,18 @@ impl fmt::Display for G2Affine {
}
}

impl AsRef<blst_p2_affine> for G2Affine {
fn as_ref(&self) -> &blst_p2_affine {
&self.0
}
}

impl AsMut<blst_p2_affine> for G2Affine {
fn as_mut(&mut self) -> &mut blst_p2_affine {
&mut self.0
}
}

impl Default for G2Affine {
fn default() -> G2Affine {
G2Affine::zero()
Expand Down Expand Up @@ -140,7 +153,6 @@ where
where
I: Iterator<Item = T>,
{
use groupy::CurveProjective;
iter.fold(Self::zero(), |acc, item| acc + item.borrow())
}
}
Expand Down Expand Up @@ -222,7 +234,7 @@ impl G2Affine {
/// Attempts to deserialize an uncompressed element.
pub fn from_uncompressed(bytes: &[u8; 192]) -> Option<Self> {
G2Affine::from_uncompressed_unchecked(bytes).and_then(|el| {
if el.is_zero() || (el.is_torsion_free() && el.is_on_curve()) {
if el.is_zero() || el.is_torsion_free() {
Some(el)
} else {
None
Expand Down Expand Up @@ -252,7 +264,7 @@ impl G2Affine {
/// Attempts to deserialize a compressed element.
pub fn from_compressed(bytes: &[u8; 96]) -> Option<Self> {
G2Affine::from_compressed_unchecked(bytes).and_then(|el| {
if el.is_zero() || (el.is_torsion_free() && el.is_on_curve()) {
if el.is_zero() || el.is_torsion_free() {
Some(el)
} else {
None
Expand Down Expand Up @@ -348,6 +360,18 @@ impl fmt::Display for G2Projective {
}
}

impl AsRef<blst_p2> for G2Projective {
fn as_ref(&self) -> &blst_p2 {
&self.0
}
}

impl AsMut<blst_p2> for G2Projective {
fn as_mut(&mut self) -> &mut blst_p2 {
&mut self.0
}
}

impl From<&G2Affine> for G2Projective {
fn from(p: &G2Affine) -> G2Projective {
let mut out = blst_p2::default();
Expand All @@ -368,8 +392,6 @@ impl Eq for G2Projective {}
impl PartialEq for G2Projective {
#[inline]
fn eq(&self, other: &Self) -> bool {
use groupy::CurveProjective;

let self_is_zero = self.is_zero();
let other_is_zero = other.is_zero();
(self_is_zero && other_is_zero)
Expand Down Expand Up @@ -565,6 +587,23 @@ impl G2Projective {
pub fn z(&self) -> Fp2 {
Fp2(self.0.z)
}

/// Hash to curve algorithm.
pub fn hash_to_curve(msg: &[u8], dst: &[u8], aug: &[u8]) -> Self {
let mut res = Self::zero();
unsafe {
blst_hash_to_g2(
&mut res.0,
msg.as_ptr(),
msg.len(),
dst.as_ptr(),
dst.len(),
aug.as_ptr(),
aug.len(),
);
}
res
}
}

impl groupy::CurveProjective for G2Projective {
Expand Down
105 changes: 105 additions & 0 deletions src/pairing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,108 @@ pub fn pairing(p: G1Affine, q: G2Affine) -> Fp12 {

out.into()
}

macro_rules! impl_pairing {
($name:ident, $p:ty, $q:ty, $aggregate:ident, $aggregated:ident) => {
/// Aggregate pairings efficiently.
#[derive(Debug)]
pub struct $name {
v: Box<[u64]>,
}

impl $name {
pub fn new(hash_or_encode: bool, dst: &[u8]) -> Self {
let v: Vec<u64> = vec![0; unsafe { blst_pairing_sizeof() } / 8];
let mut obj = Self {
v: v.into_boxed_slice(),
};
obj.init(hash_or_encode, dst);
obj
}

pub fn init(&mut self, hash_or_encode: bool, dst: &[u8]) {
unsafe { blst_pairing_init(self.ctx(), hash_or_encode, dst.as_ptr(), dst.len()) }
}

fn ctx(&mut self) -> *mut blst_pairing {
self.v.as_mut_ptr() as *mut blst_pairing
}

fn const_ctx(&self) -> *const blst_pairing {
self.v.as_ptr() as *const blst_pairing
}

pub fn aggregate(
&mut self,
pk: &$p,
sig: Option<&$q>,
msg: &[u8],
aug: &[u8],
) -> Result<(), BLST_ERROR> {
let res = unsafe {
$aggregate(
self.ctx(),
&pk.0,
match sig {
Some(sig) => &sig.0,
None => std::ptr::null(),
},
msg.as_ptr(),
msg.len(),
aug.as_ptr(),
aug.len(),
)
};
if res == BLST_ERROR::BLST_SUCCESS {
Ok(())
} else {
Err(res)
}
}

pub fn aggregated(gtsig: &mut Fp12, sig: &$q) {
unsafe { $aggregated(&mut gtsig.0, &sig.0) }
}

pub fn commit(&mut self) {
unsafe { blst_pairing_commit(self.ctx()) }
}

pub fn merge(&mut self, ctx1: &Self) -> Result<(), BLST_ERROR> {
let res = unsafe { blst_pairing_merge(self.ctx(), ctx1.const_ctx()) };
if res == BLST_ERROR::BLST_SUCCESS {
Ok(())
} else {
Err(res)
}
}

pub fn finalverify(&self, gtsig: Option<&Fp12>) -> bool {
unsafe {
blst_pairing_finalverify(
self.const_ctx(),
match gtsig {
Some(ref gtsig) => &gtsig.0,
None => std::ptr::null(),
},
)
}
}
}
};
}

impl_pairing!(
PairingG1G2,
G1Affine,
G2Affine,
blst_pairing_aggregate_pk_in_g1,
blst_aggregated_in_g2
);
impl_pairing!(
PairingG2G1,
G2Affine,
G1Affine,
blst_pairing_aggregate_pk_in_g2,
blst_aggregated_in_g1
);
23 changes: 23 additions & 0 deletions src/scalar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,29 @@ impl AsMut<[u64]> for ScalarRepr {
}
}

impl AsRef<blst_fr> for Scalar {
fn as_ref(&self) -> &blst_fr {
&self.0
}
}

impl AsMut<blst_fr> for Scalar {
fn as_mut(&mut self) -> &mut blst_fr {
&mut self.0
}
}

impl Into<blst_scalar> for Scalar {
fn into(self) -> blst_scalar {
let mut out = blst_scalar::default();
unsafe {
blst_scalar_from_fr(&mut out, &self.0);
}

out
}
}

const LIMBS: usize = 4;
const LIMB_BITS: usize = 64;

Expand Down

0 comments on commit ea31380

Please sign in to comment.