use crate::helpers::{KEYGEN_SALT, get_crypto_rng};
use crate::impls::inner_types::*;
use crate::*;
use core::fmt::{self, Formatter};
use rand::Rng;
use rand_core::{CryptoRng, RngCore};
use serde::de::{SeqAccess, Visitor};
use subtle::CtOption;
use vsss_rs::*;
pub const SECRET_KEY_BYTES: usize = 32;
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum SecretKeyEnum {
G1(SecretKey<Bls12381G1Impl>),
G2(SecretKey<Bls12381G2Impl>),
}
impl Serialize for SecretKeyEnum {
fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
match self {
SecretKeyEnum::G1(sk) => (Bls12381::G1, sk).serialize(s),
SecretKeyEnum::G2(sk) => (Bls12381::G2, sk).serialize(s),
}
}
}
impl<'de> Deserialize<'de> for SecretKeyEnum {
fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
struct SecretKeyEnumVisitor;
impl<'de> Visitor<'de> for SecretKeyEnumVisitor {
type Value = SecretKeyEnum;
fn expecting(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "a tuple of the type and secret key")
}
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
where
A: SeqAccess<'de>,
{
let ee = seq
.next_element::<Bls12381>()?
.ok_or_else(|| serde::de::Error::invalid_length(0, &self))?;
match ee {
Bls12381::G1 => {
let sk = seq
.next_element::<SecretKey<Bls12381G1Impl>>()?
.ok_or_else(|| serde::de::Error::invalid_length(1, &self))?;
Ok(SecretKeyEnum::G1(sk))
}
Bls12381::G2 => {
let sk = seq
.next_element::<SecretKey<Bls12381G2Impl>>()?
.ok_or_else(|| serde::de::Error::invalid_length(1, &self))?;
Ok(SecretKeyEnum::G2(sk))
}
}
}
}
d.deserialize_tuple(2, SecretKeyEnumVisitor)
}
}
impl Default for SecretKeyEnum {
fn default() -> Self {
Self::G1(SecretKey(Scalar::default()))
}
}
impl From<&SecretKeyEnum> for Vec<u8> {
fn from(value: &SecretKeyEnum) -> Self {
let (tt, mut output) = match value {
SecretKeyEnum::G1(sk) => (Bls12381::G1, Vec::from(sk)),
SecretKeyEnum::G2(sk) => (Bls12381::G2, Vec::from(sk)),
};
output.insert(0, tt as u8);
output
}
}
impl TryFrom<&[u8]> for SecretKeyEnum {
type Error = BlsError;
fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
let ee = Bls12381::try_from(value[0])?;
match ee {
Bls12381::G1 => {
let sk = SecretKey::<Bls12381G1Impl>::try_from(&value[1..])?;
Ok(SecretKeyEnum::G1(sk))
}
Bls12381::G2 => {
let sk = SecretKey::<Bls12381G2Impl>::try_from(&value[1..])?;
Ok(SecretKeyEnum::G2(sk))
}
}
}
}
impl_from_derivatives!(SecretKeyEnum);
impl SecretKeyEnum {
pub fn new(t: Bls12381) -> Self {
match t {
Bls12381::G1 => SecretKeyEnum::G1(SecretKey::new()),
Bls12381::G2 => SecretKeyEnum::G2(SecretKey::new()),
}
}
pub fn from_hash<B: AsRef<[u8]>>(t: Bls12381, data: B) -> Self {
match t {
Bls12381::G1 => SecretKeyEnum::G1(SecretKey::from_hash(data)),
Bls12381::G2 => SecretKeyEnum::G2(SecretKey::from_hash(data)),
}
}
pub fn random(t: Bls12381, rng: impl RngCore + CryptoRng) -> Self {
match t {
Bls12381::G1 => SecretKeyEnum::G1(SecretKey::random(rng)),
Bls12381::G2 => SecretKeyEnum::G2(SecretKey::random(rng)),
}
}
pub fn to_be_bytes(&self) -> Vec<u8> {
let (t, mut output) = match self {
SecretKeyEnum::G1(sk) => (Bls12381::G1, Vec::from(sk.to_be_bytes())),
SecretKeyEnum::G2(sk) => (Bls12381::G2, Vec::from(sk.to_be_bytes())),
};
output.insert(0, t as u8);
output
}
pub fn to_le_bytes(&self) -> Vec<u8> {
let (t, mut output) = match self {
SecretKeyEnum::G1(sk) => (Bls12381::G1, Vec::from(sk.to_le_bytes())),
SecretKeyEnum::G2(sk) => (Bls12381::G2, Vec::from(sk.to_le_bytes())),
};
output.insert(0, t as u8);
output
}
pub fn from_be_bytes(bytes: &[u8]) -> CtOption<Self> {
let t = match Bls12381::try_from(bytes[0]) {
Ok(t) => t,
Err(_) => return CtOption::new(Self::default(), Choice::from(0u8)),
};
match (&bytes[1..]).try_into() {
Ok(sk) => match t {
Bls12381::G1 => {
let ct_sk = SecretKey::from_be_bytes(&sk);
let choice = ct_sk.is_some();
let val = if choice.into() {
SecretKeyEnum::G1(ct_sk.unwrap())
} else {
Self::default()
};
CtOption::new(val, choice)
}
Bls12381::G2 => {
let ct_sk = SecretKey::from_be_bytes(&sk);
let choice = ct_sk.is_some();
let val = if choice.into() {
SecretKeyEnum::G2(ct_sk.unwrap())
} else {
Self::default()
};
CtOption::new(val, choice)
}
},
Err(_) => CtOption::new(Self::default(), Choice::from(0u8)),
}
}
pub fn from_le_bytes(bytes: &[u8]) -> CtOption<Self> {
let t = match Bls12381::try_from(bytes[0]) {
Ok(t) => t,
Err(_) => return CtOption::new(Self::default(), Choice::from(0u8)),
};
match (&bytes[1..]).try_into() {
Ok(sk) => match t {
Bls12381::G1 => {
let ct_sk = SecretKey::from_le_bytes(&sk);
let choice = ct_sk.is_some();
let val = if choice.into() {
SecretKeyEnum::G1(ct_sk.unwrap())
} else {
Self::default()
};
CtOption::new(val, choice)
}
Bls12381::G2 => {
let ct_sk = SecretKey::from_le_bytes(&sk);
let choice = ct_sk.is_some();
let val = if choice.into() {
SecretKeyEnum::G2(ct_sk.unwrap())
} else {
Self::default()
};
CtOption::new(val, choice)
}
},
Err(_) => CtOption::new(Self::default(), Choice::from(0u8)),
}
}
}
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
pub struct SecretKey<C: BlsSignatureImpl>(
#[serde(serialize_with = "traits::scalar::serialize::<C, _>")]
#[serde(deserialize_with = "traits::scalar::deserialize::<C, _>")]
pub <<C as Pairing>::PublicKey as Group>::Scalar,
);
impl<C: BlsSignatureImpl> From<SecretKey<C>> for [u8; SECRET_KEY_BYTES] {
fn from(sk: SecretKey<C>) -> [u8; SECRET_KEY_BYTES] {
sk.to_be_bytes()
}
}
impl<'a, C: BlsSignatureImpl> From<&'a SecretKey<C>> for [u8; SECRET_KEY_BYTES] {
fn from(sk: &'a SecretKey<C>) -> [u8; SECRET_KEY_BYTES] {
sk.to_be_bytes()
}
}
impl_from_derivatives_generic!(SecretKey);
impl<C: BlsSignatureImpl> From<&SecretKey<C>> for Vec<u8> {
fn from(value: &SecretKey<C>) -> Self {
value.to_be_bytes().to_vec()
}
}
impl<C: BlsSignatureImpl> TryFrom<&[u8]> for SecretKey<C> {
type Error = BlsError;
fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
let bytes = <[u8; 32]>::try_from(value)
.map_err(|_| BlsError::InvalidInputs("Invalid secret key bytes".to_string()))?;
Option::from(Self::from_be_bytes(&bytes))
.ok_or_else(|| BlsError::InvalidInputs("Invalid secret key bytes".to_string()))
}
}
impl<C: BlsSignatureImpl> SecretKey<C> {
pub fn new() -> Self {
Self::random(get_crypto_rng())
}
pub fn from_hash<B: AsRef<[u8]>>(data: B) -> Self {
Self(<C as HashToScalar>::hash_to_scalar(
data.as_ref(),
KEYGEN_SALT,
))
}
pub fn random(mut rng: impl RngCore + CryptoRng) -> Self {
Self(<C as HashToScalar>::hash_to_scalar(
rng.r#gen::<[u8; SECRET_KEY_BYTES]>(),
KEYGEN_SALT,
))
}
pub fn to_be_bytes(&self) -> [u8; SECRET_KEY_BYTES] {
scalar_to_be_bytes::<C, SECRET_KEY_BYTES>(self.0)
}
pub fn to_le_bytes(&self) -> [u8; SECRET_KEY_BYTES] {
scalar_to_le_bytes::<C, SECRET_KEY_BYTES>(self.0)
}
pub fn from_be_bytes(bytes: &[u8; SECRET_KEY_BYTES]) -> CtOption<Self> {
scalar_from_be_bytes::<C, SECRET_KEY_BYTES>(bytes).map(Self)
}
pub fn from_le_bytes(bytes: &[u8; SECRET_KEY_BYTES]) -> CtOption<Self> {
scalar_from_le_bytes::<C, SECRET_KEY_BYTES>(bytes).map(Self)
}
pub fn split(&self, threshold: usize, limit: usize) -> BlsResult<Vec<SecretKeyShare<C>>> {
self.split_with_rng(threshold, limit, get_crypto_rng())
}
pub fn split_with_rng(
&self,
threshold: usize,
limit: usize,
rng: impl RngCore + CryptoRng,
) -> BlsResult<Vec<SecretKeyShare<C>>> {
let secret = IdentifierPrimeField(self.0);
let shares =
shamir::split_secret::<<C as Pairing>::SecretKeyShare>(threshold, limit, &secret, rng)?
.into_iter()
.map(SecretKeyShare)
.collect::<Vec<_>>();
Ok(shares)
}
pub fn combine(shares: &[SecretKeyShare<C>]) -> BlsResult<Self> {
let ss = shares.iter().map(|s| s.0.clone()).collect::<Vec<_>>();
let secret = ss.combine()?;
Ok(Self(secret.0))
}
pub fn public_key(&self) -> PublicKey<C> {
PublicKey(<C as BlsSignatureCore>::public_key(&self.0))
}
pub fn proof_of_possession(&self) -> BlsResult<ProofOfPossession<C>> {
Ok(ProofOfPossession(<C as BlsSignaturePop>::pop_prove(
&self.0,
)?))
}
pub fn sign(&self, scheme: SignatureSchemes, msg: &[u8]) -> BlsResult<Signature<C>> {
match scheme {
SignatureSchemes::Basic => {
let inner = <C as BlsSignatureBasic>::sign(&self.0, msg)?;
Ok(Signature::Basic(inner))
}
SignatureSchemes::MessageAugmentation => {
let inner = <C as BlsSignatureMessageAugmentation>::sign(&self.0, msg)?;
Ok(Signature::MessageAugmentation(inner))
}
SignatureSchemes::ProofOfPossession => {
let inner = <C as BlsSignaturePop>::sign(&self.0, msg)?;
Ok(Signature::ProofOfPossession(inner))
}
}
}
pub fn sign_decryption_key<B: AsRef<[u8]>>(
&self,
ciphertext: &SignCryptCiphertext<C>,
) -> SignCryptDecryptionKey<C> {
SignCryptDecryptionKey(ciphertext.u * self.0)
}
}