use crate::{Result, VeilCryptoError};
use k256::{
elliptic_curve::{sec1::ToEncodedPoint, PrimeField},
AffinePoint, EncodedPoint, ProjectivePoint, Scalar,
};
use sha2::{Digest, Sha256};
pub(crate) fn hash_to_curve(data: &[u8]) -> Result<ProjectivePoint> {
const SAFETY: usize = 128;
let mut hash = Sha256::digest(data);
for _ in 0..SAFETY {
let mut compressed = [0u8; 33];
compressed[0] = 0x02; compressed[1..].copy_from_slice(&hash);
if let Ok(encoded) = EncodedPoint::from_bytes(&compressed) {
if let Ok(point) = AffinePoint::try_from(&encoded) {
return Ok(point.into());
}
}
hash = Sha256::digest(&hash);
}
Err(VeilCryptoError::Other(
format!("hash_to_curve failed: no valid point found after {} attempts", SAFETY),
))
}
pub fn get_keyimage(pk_bytes: &[u8], sk_bytes: &[u8]) -> Result<Vec<u8>> {
let hashed_point = hash_to_curve(pk_bytes)?;
if sk_bytes.len() != 32 {
return Err(VeilCryptoError::InvalidSecretKey);
}
let sk_array: [u8; 32] = sk_bytes
.try_into()
.map_err(|_| VeilCryptoError::InvalidSecretKey)?;
let scalar = Scalar::from_repr(sk_array.into())
.into_option()
.ok_or(VeilCryptoError::InvalidSecretKey)?;
let key_image = hashed_point * scalar;
let compressed = key_image.to_affine().to_encoded_point(true);
Ok(compressed.as_bytes().to_vec())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_hash_to_curve_basic() {
let data = b"test data";
let result = hash_to_curve(data);
assert!(result.is_ok());
let point = result.unwrap();
assert_ne!(point, ProjectivePoint::IDENTITY);
}
#[test]
fn test_hash_to_curve_deterministic() {
let data = b"test data";
let result1 = hash_to_curve(data).unwrap();
let result2 = hash_to_curve(data).unwrap();
assert_eq!(result1, result2);
}
#[test]
fn test_hash_to_curve_different_inputs() {
let data1 = b"test data 1";
let data2 = b"test data 2";
let result1 = hash_to_curve(data1).unwrap();
let result2 = hash_to_curve(data2).unwrap();
assert_ne!(result1, result2);
}
#[test]
fn test_keyimage_basic() {
let pk = hex::decode("0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798").unwrap();
let sk = hex::decode("0000000000000000000000000000000000000000000000000000000000000001").unwrap();
let result = get_keyimage(&pk, &sk);
assert!(result.is_ok());
assert_eq!(result.unwrap().len(), 33);
}
#[test]
fn test_keyimage_deterministic() {
let pk = hex::decode("0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798").unwrap();
let sk = hex::decode("0000000000000000000000000000000000000000000000000000000000000001").unwrap();
let result1 = get_keyimage(&pk, &sk).unwrap();
let result2 = get_keyimage(&pk, &sk).unwrap();
assert_eq!(result1, result2);
}
#[test]
fn test_keyimage_invalid_sk_length() {
let pk = hex::decode("0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798").unwrap();
let sk = vec![0u8; 31];
let result = get_keyimage(&pk, &sk);
assert!(result.is_err());
}
#[test]
fn test_keyimage_vector_1() {
let pk = hex::decode("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20").unwrap();
let sk = hex::decode("2122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f40").unwrap();
let expected = hex::decode("02ad397571b22342ecbcf22e51f85998fb8bc5696393fead098a87bb9b5a7cfa08").unwrap();
let result = get_keyimage(&pk, &sk).unwrap();
assert_eq!(
result, expected,
"Key image doesn't match C implementation!\nExpected: {}\nGot: {}",
hex::encode(&expected),
hex::encode(&result)
);
}
#[test]
fn test_keyimage_vector_2() {
let pk = hex::decode("0284bf7562262bbd6940085748f3be6afa52ae317155181ece31b66351ccffa4b0").unwrap();
let sk = hex::decode("0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20").unwrap();
let expected = hex::decode("038da64d9766497e356dc36a06c07b30e83170eb0430527fc7018445413db8ac6c").unwrap();
let result = get_keyimage(&pk, &sk).unwrap();
assert_eq!(
result, expected,
"Key image vector 2 doesn't match!\nExpected: {}\nGot: {}",
hex::encode(&expected),
hex::encode(&result)
);
}
#[test]
fn test_keyimage_vector_3() {
let pk = hex::decode("03020406080a0c0e10121416181a1c1e20222426282a2c2e30323436383a3c3e40").unwrap();
let sk = hex::decode("05060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f2021222324").unwrap();
let expected = hex::decode("02028e081e9a9596367d2044260c61da4f4cbd44ca39ed7a2c93d29a310c08d906").unwrap();
let result = get_keyimage(&pk, &sk).unwrap();
assert_eq!(
result, expected,
"Key image vector 3 doesn't match!\nExpected: {}\nGot: {}",
hex::encode(&expected),
hex::encode(&result)
);
}
}