1use elastic_elgamal::{Ciphertext, group::Generic};
2use p256::{
3 AffinePoint, NistP256, ProjectivePoint, Sec1Point,
4 ecdsa::{
5 Signature, SigningKey, VerifyingKey,
6 signature::{Signer, Verifier},
7 },
8 elliptic_curve::sec1::{FromSec1Point, ToSec1Point},
9};
10
11use std::sync::OnceLock;
12
13pub type PublicKey = elastic_elgamal::PublicKey<Generic<NistP256>>;
14pub type SecretKey = elastic_elgamal::SecretKey<Generic<NistP256>>;
15pub type Keypair = elastic_elgamal::Keypair<Generic<NistP256>>;
17
18pub const SCALAR_SIZE: usize = 32;
19pub const SIGNATURE_SIZE: usize = 64;
20
21pub trait ToUntaggedBytes {
22 fn to_untagged_bytes(&self) -> Box<[u8]>;
23}
24
25impl<T: ToSec1Point<NistP256>> ToUntaggedBytes for T {
26 fn to_untagged_bytes(&self) -> Box<[u8]> {
27 self.to_sec1_point(false)
28 .as_bytes()
29 .iter()
30 .copied()
31 .skip(1) .collect()
33 }
34}
35
36pub trait FromBytes
37where
38 Self: Sized,
39{
40 type Error;
41
42 fn from_bytes(bytes: &[u8]) -> Result<Self, Self::Error>;
43}
44
45impl FromBytes for Keypair {
46 type Error = crate::Error;
47
48 fn from_bytes(bytes: &[u8]) -> Result<Self, Self::Error> {
49 Ok(Keypair::from(
50 SecretKey::from_bytes(bytes).ok_or(crate::Error::P256DecodeError)?,
51 ))
52 }
53}
54
55impl FromBytes for VerifyingKey {
56 type Error = crate::Error;
57
58 fn from_bytes(bytes: &[u8]) -> Result<Self, Self::Error> {
59 let point = Sec1Point::from_untagged_bytes(
60 bytes.try_into().or(Err(crate::Error::P256DecodeError))?,
61 );
62 let point = AffinePoint::from_sec1_point(&point)
63 .into_option()
64 .ok_or(crate::Error::P256DecodeError)?;
65
66 VerifyingKey::from_affine(point).or(Err(crate::Error::P256DecodeError))
67 }
68}
69
70pub fn wmrm_public_key() -> &'static PublicKey {
71 static CELL: OnceLock<PublicKey> = OnceLock::new();
72
73 CELL.get_or_init(|| {
74 const WMRM_KEY: [u8; 33] = [
75 0x02, 0xc8, 0xb6, 0xaf, 0x16, 0xee, 0x94, 0x1a, 0xad, 0xaa, 0x53, 0x89, 0xb4, 0xaf,
76 0x2c, 0x10, 0xe3, 0x56, 0xbe, 0x42, 0xaf, 0x17, 0x5e, 0xf3, 0xfa, 0xce, 0x93, 0x25,
77 0x4e, 0x7b, 0x0b, 0x3d, 0x9b,
78 ];
79
80 PublicKey::from_bytes(&WMRM_KEY).unwrap()
81 })
82}
83
84pub fn encrypt(public_key: &PublicKey, plaintext: ProjectivePoint) -> Vec<u8> {
85 let mut rng = rand::rng();
86 let ciphertext = public_key.encrypt_element(plaintext, &mut rng);
87
88 let point1 = ciphertext.random_element().to_untagged_bytes();
89 let point2 = ciphertext.blinded_element().to_untagged_bytes();
90
91 [point1, point2].concat()
92}
93
94pub fn decrypt(private_key: &SecretKey, ciphertext: &[u8]) -> Result<Vec<u8>, crate::Error> {
95 let random_element = Sec1Point::from_untagged_bytes(
96 ciphertext
97 .get(..64)
98 .ok_or(crate::Error::SliceOutOfBoundsError(
99 "ciphertext",
100 ciphertext.len(),
101 ))?
102 .try_into()
103 .or(Err(crate::Error::P256DecodeError))?,
104 );
105 let random_element = AffinePoint::from_sec1_point(&random_element)
106 .into_option()
107 .ok_or(crate::Error::P256DecodeError)?;
108
109 let blinded_element = Sec1Point::from_untagged_bytes(
110 ciphertext
111 .get(64..128)
112 .ok_or(crate::Error::SliceOutOfBoundsError(
113 "ciphertext",
114 ciphertext.len(),
115 ))?
116 .try_into()
117 .or(Err(crate::Error::P256DecodeError))?,
118 );
119 let blinded_element = AffinePoint::from_sec1_point(&blinded_element)
120 .into_option()
121 .ok_or(crate::Error::P256DecodeError)?;
122
123 let encrypted = Ciphertext::from_elements(random_element.into(), blinded_element.into());
124
125 Ok(private_key
126 .decrypt_to_element(encrypted)
127 .to_untagged_bytes()
128 .to_vec())
129}
130
131pub fn verify(
132 verifying_key: &VerifyingKey,
133 msg: &[u8],
134 signature: &[u8],
135) -> Result<(), p256::ecdsa::Error> {
136 let signature = Signature::from_slice(signature)?;
137 verifying_key.verify(msg, &signature)
138}
139
140pub fn sign(signing_key: &SigningKey, msg: &[u8]) -> Vec<u8> {
141 let signature: Signature = signing_key.sign(msg);
142 signature.to_bytes().to_vec()
143}
144
145#[cfg(test)]
146mod test {
147 use crate::{
148 Keypair,
149 crypto::ecc_p256::{FromBytes, SecretKey, ToUntaggedBytes, decrypt},
150 };
151 use p256::ecdsa::VerifyingKey;
152
153 #[test]
154 fn create_invalid_verifying_key() {
155 assert!(matches!(
156 VerifyingKey::from_bytes(&[1]),
157 Err(crate::Error::P256DecodeError)
158 ));
159 }
160
161 #[test]
162 fn try_to_decrypt_too_short_ciphertext() {
163 let sk = SecretKey::from_bytes(&[1u8; 32]).unwrap();
164
165 assert!(matches!(
166 decrypt(&sk, &[1]),
167 Err(crate::Error::SliceOutOfBoundsError(_, _))
168 ));
169 }
170
171 #[test]
172 fn decrypt_long_ciphertext() {
173 let sk = SecretKey::from_bytes(&[1u8; 32]).unwrap();
174 let kp = Keypair::from(sk.clone());
175
176 let mut point = kp.public().as_element().to_untagged_bytes().to_vec();
177 point.append(&mut point.clone());
178
179 let expected = vec![
180 172, 161, 83, 0, 40, 73, 212, 190, 29, 204, 157, 78, 217, 152, 216, 235, 155, 39, 228,
181 115, 176, 146, 44, 117, 228, 161, 45, 97, 177, 206, 222, 39, 112, 171, 121, 124, 145,
182 154, 37, 179, 108, 74, 77, 247, 132, 44, 68, 197, 162, 252, 131, 221, 46, 117, 145, 82,
183 33, 147, 21, 83, 103, 237, 70, 93,
184 ];
185
186 assert_eq!(decrypt(&sk, &point).unwrap(), expected);
187 point.append(&mut vec![1u8; 32]);
188 assert_eq!(decrypt(&sk, &point).unwrap(), expected);
189 }
190}