use k256::elliptic_curve::bigint::ArrayEncoding;
use k256::elliptic_curve::ops::Reduce;
use k256::sha2::{digest::Output, Digest, Sha256}; use k256::ProjectivePoint;
use k256::Scalar;
use k256::U256;
use signature::RandomizedSigner;
pub use k256::{AffinePoint, NonZeroScalar, SecretKey};
pub use rand_core::CryptoRngCore;
#[cfg(feature = "serde")]
pub use serde::{Deserialize, Serialize};
mod utils;
use utils::*;
pub mod randomizedsigner;
use randomizedsigner::PlumeSigner;
pub const DST: &[u8] = b"QUUX-V01-CS02-with-secp256k1_XMD:SHA-256_SSWU_RO_";
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct PlumeSignature {
pub message: Vec<u8>,
pub pk: AffinePoint,
pub nullifier: AffinePoint,
pub c: NonZeroScalar,
pub s: NonZeroScalar,
pub v1specific: Option<PlumeSignatureV1Fields>,
}
#[derive(Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct PlumeSignatureV1Fields {
pub r_point: AffinePoint,
pub hashed_to_curve_r: AffinePoint,
}
impl PlumeSignature {
pub fn verify(&self) -> bool {
let c_scalar = *self.c;
let r_point = (ProjectivePoint::GENERATOR * *self.s) - (self.pk * (c_scalar));
let hashed_to_curve = hash_to_curve(&self.message, &self.pk.into());
if hashed_to_curve.is_err() {
return false;
}
let hashed_to_curve = hashed_to_curve.unwrap();
let hashed_to_curve_r = hashed_to_curve * *self.s - self.nullifier * (c_scalar);
if let Some(PlumeSignatureV1Fields {
r_point: sig_r_point,
hashed_to_curve_r: sig_hashed_to_curve_r,
}) = self.v1specific
{
if r_point != sig_r_point {
return false;
}
if hashed_to_curve_r != sig_hashed_to_curve_r {
return false;
}
c_scalar
== Scalar::reduce(U256::from_be_byte_array(c_sha256_vec_signal(vec![
&ProjectivePoint::GENERATOR,
&self.pk.into(),
&hashed_to_curve,
&self.nullifier.into(),
&r_point,
&hashed_to_curve_r,
])))
} else {
c_scalar
== Scalar::reduce(U256::from_be_byte_array(c_sha256_vec_signal(vec![
&self.nullifier.into(),
&r_point,
&hashed_to_curve_r,
])))
}
}
pub fn sign_v1(secret_key: &SecretKey, msg: &[u8], rng: &mut impl CryptoRngCore) -> Self {
PlumeSigner::new(secret_key, true).sign_with_rng(rng, msg)
}
pub fn sign_v2(secret_key: &SecretKey, msg: &[u8], rng: &mut impl CryptoRngCore) -> Self {
PlumeSigner::new(secret_key, false).sign_with_rng(rng, msg)
}
}
fn c_sha256_vec_signal(values: Vec<&ProjectivePoint>) -> Output<Sha256> {
let preimage_vec = values
.into_iter()
.map(encode_pt)
.collect::<Vec<_>>()
.concat();
let mut sha256_hasher = Sha256::new();
sha256_hasher.update(preimage_vec.as_slice());
sha256_hasher.finalize()
}
#[cfg(test)]
mod tests {
use super::*;
use hex_literal::hex;
#[test]
fn test_encode_pt() {
let g_as_bytes = encode_pt(&ProjectivePoint::GENERATOR);
assert_eq!(
hex::encode(g_as_bytes),
"0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798"
);
}
fn byte_array_to_scalar(bytes: &[u8]) -> Scalar {
assert!(bytes.len() == 32);
let mut res = Scalar::from(0u64);
let window_size = Scalar::from(256u64);
for byte in bytes.iter() {
res *= window_size;
res += Scalar::from(*byte as u64);
}
res
}
#[test]
fn test_byte_array_to_scalar() {
let scalar = byte_array_to_scalar(&hex!(
"c6a7fc2c926ddbaf20731a479fb6566f2daa5514baae5223fe3b32edbce83254"
));
assert_eq!(
hex::encode(scalar.to_bytes()),
"c6a7fc2c926ddbaf20731a479fb6566f2daa5514baae5223fe3b32edbce83254"
);
}
}