#![cfg_attr(not(feature = "std"), no_std)]
use fr::FrElement;
use rand_core::CryptoRngCore;
use cryptix_bigint::property::IsBigInt;
use cryptix_ecc::CurvePoint;
use cryptix_pairing::Pairing;
use cryptix_field::field::{montgomery::MontgomeryOps, MulInverse};
use cryptix_bn254::{pairing::{e1::BN254Fp, e2::BN254Fp2, o_ate::OptimalAte}, galoisfield::{U256, fp12::Fp12Element}};
use sha2::Digest;
pub mod fr;
#[derive(Debug)]
pub struct BLMQ<R: CryptoRngCore> {
msk: FrElement,
g: Fp12Element,
p_pub: BN254Fp2,
rng: R
}
#[derive(Debug, Clone, Copy)]
pub struct Sigma {
pub h: FrElement,
pub s: BN254Fp
}
impl<R: CryptoRngCore> BLMQ<R> {
pub fn new(mut rng: R) -> Self {
let msk = FrElement::rand(&mut rng);
Self {
msk, rng,
p_pub: BN254Fp2::GENERATOR.scalar_mul(msk.repr()).normalize(),
g: OptimalAte::pairing(BN254Fp::GENERATOR, BN254Fp2::GENERATOR)
}
}
pub fn extract(&self, id: &[u8]) -> (FrElement, BN254Fp) {
let pk = Self::hash_to_field(id);
let t = (pk + self.msk).mont_form().mont_inv().mont_rdc();
let sk = BN254Fp::GENERATOR.scalar_mul(t.repr()).normalize();
debug_assert!(sk.on_curve(), "dID not on curve!");
(t, sk)
}
fn hash_to_field(buf: &[u8]) -> FrElement {
let hash = sha2::Sha256::digest(buf);
U256::from_bytes(&hash).into()
}
fn msg_hash_field(u: Fp12Element, msg: &[u8]) -> FrElement {
const HASH_LEN: usize = 32;
const FP12_BYTE_LEN: usize = U256::BYTE_LEN * 12;
const BUF_LEN: usize = FP12_BYTE_LEN + HASH_LEN;
let mut buf = [0_u8; BUF_LEN];
let hash = sha2::Sha256::digest(msg);
let u_bytes: [u8; FP12_BYTE_LEN] = u.into();
buf[..FP12_BYTE_LEN].copy_from_slice(&u_bytes);
buf[FP12_BYTE_LEN..BUF_LEN].copy_from_slice(&hash);
Self::hash_to_field(&buf)
}
pub fn sign(&mut self, sk: BN254Fp, msg: &[u8]) -> Sigma {
let r = FrElement::rand(&mut self.rng);
let u = self.g.mont_rdc().mont_exp(r.repr());
let h = Self::msg_hash_field(u, msg);
let t = h + r;
let s = sk.scalar_mul(t.repr()).normalize();
debug_assert!(s.on_curve(), "S not on curve");
Sigma { h, s }
}
pub fn verify(&self, sig: &Sigma, id: &[u8], msg: &[u8]) -> bool {
let pk = Self::hash_to_field(id);
let w = self.g.mont_rdc().mont_exp(sig.h.repr()).mul_inv();
let u = OptimalAte::pairing(
sig.s,
(BN254Fp2::GENERATOR.scalar_mul(pk.repr()) + self.p_pub).normalize()
).mont_mul(w);
let h = Self::msg_hash_field(u, msg);
h == sig.h
}
}