1use elastic_elgamal::{Ciphertext, group::Generic};
2use p256::{
3 AffinePoint, EncodedPoint, NistP256, ProjectivePoint,
4 ecdsa::{
5 Signature, SigningKey, VerifyingKey,
6 signature::{Signer, Verifier},
7 },
8 elliptic_curve::sec1::{FromEncodedPoint, ToEncodedPoint},
9};
10
11use std::{ptr::copy_nonoverlapping, 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: ToEncodedPoint<NistP256>> ToUntaggedBytes for T {
26 fn to_untagged_bytes(&self) -> Box<[u8]> {
27 self.to_encoded_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 if bytes.len() != 64 {
60 return Err(crate::Error::P256DecodeError);
61 }
62
63 let point = EncodedPoint::from_untagged_bytes(bytes.into());
64 let point = AffinePoint::from_encoded_point(&point)
65 .into_option()
66 .ok_or(crate::Error::P256DecodeError)?;
67
68 VerifyingKey::from_affine(point).or(Err(crate::Error::P256DecodeError))
69 }
70}
71
72pub fn wmrm_public_key() -> &'static PublicKey {
73 static CELL: OnceLock<PublicKey> = OnceLock::new();
74
75 CELL.get_or_init(|| {
76 const WMRM_KEY: [u8; 33] = [
77 0x02, 0xc8, 0xb6, 0xaf, 0x16, 0xee, 0x94, 0x1a, 0xad, 0xaa, 0x53, 0x89, 0xb4, 0xaf,
78 0x2c, 0x10, 0xe3, 0x56, 0xbe, 0x42, 0xaf, 0x17, 0x5e, 0xf3, 0xfa, 0xce, 0x93, 0x25,
79 0x4e, 0x7b, 0x0b, 0x3d, 0x9b,
80 ];
81
82 PublicKey::from_bytes(&WMRM_KEY).unwrap()
83 })
84}
85
86pub fn encrypt(public_key: &PublicKey, plaintext: ProjectivePoint) -> Vec<u8> {
87 let mut rng = rand::thread_rng();
88 let ciphertext = public_key.encrypt_element(plaintext, &mut rng);
89
90 let point1 = ciphertext.random_element().to_untagged_bytes();
91 let point2 = ciphertext.blinded_element().to_untagged_bytes();
92
93 [point1, point2].concat()
94}
95
96pub fn decrypt(private_key: &SecretKey, ciphertext: &[u8]) -> Result<Vec<u8>, crate::Error> {
97 let random_element = EncodedPoint::from_untagged_bytes(
98 ciphertext
99 .get(..64)
100 .ok_or(crate::Error::SliceOutOfBoundsError(
101 "ciphertext",
102 ciphertext.len(),
103 ))?
104 .into(),
105 );
106 let random_element = AffinePoint::from_encoded_point(&random_element)
107 .into_option()
108 .ok_or(crate::Error::P256DecodeError)?;
109
110 let blinded_element = EncodedPoint::from_untagged_bytes(
111 ciphertext
112 .get(64..128)
113 .ok_or(crate::Error::SliceOutOfBoundsError(
114 "ciphertext",
115 ciphertext.len(),
116 ))?
117 .into(),
118 );
119 let blinded_element = AffinePoint::from_encoded_point(&blinded_element)
120 .into_option()
121 .ok_or(crate::Error::P256DecodeError)?;
122
123 let encrypted: Ciphertext<Generic<NistP256>> = Ciphertext::zero();
124
125 unsafe {
127 copy_nonoverlapping(
128 &random_element.into(),
129 encrypted.random_element() as *const ProjectivePoint as *mut ProjectivePoint,
130 1,
131 );
132 copy_nonoverlapping(
133 &blinded_element.into(),
134 encrypted.blinded_element() as *const ProjectivePoint as *mut ProjectivePoint,
135 1,
136 );
137 };
138
139 Ok(private_key
140 .decrypt_to_element(encrypted)
141 .to_untagged_bytes()
142 .to_vec())
143}
144
145pub fn verify(
146 verifying_key: &VerifyingKey,
147 msg: &[u8],
148 signature: &[u8],
149) -> Result<(), p256::ecdsa::Error> {
150 let signature = Signature::from_slice(signature)?;
151 verifying_key.verify(msg, &signature)
152}
153
154pub fn sign(signing_key: &SigningKey, msg: &[u8]) -> Vec<u8> {
155 let signature: Signature = signing_key.sign(msg);
156 signature.to_bytes().to_vec()
157}
158
159#[cfg(test)]
160mod test {
161 use crate::{
162 Keypair,
163 crypto::ecc_p256::{FromBytes, SecretKey, ToUntaggedBytes, decrypt},
164 };
165 use p256::ecdsa::VerifyingKey;
166
167 #[test]
168 fn create_invalid_verifying_key() {
169 assert!(matches!(
170 VerifyingKey::from_bytes(&[1]),
171 Err(crate::Error::P256DecodeError)
172 ));
173 }
174
175 #[test]
176 fn try_to_decrypt_too_short_ciphertext() {
177 let sk = SecretKey::from_bytes(&[1u8; 32]).unwrap();
178
179 assert!(matches!(
180 decrypt(&sk, &[1]),
181 Err(crate::Error::SliceOutOfBoundsError(_, _))
182 ));
183 }
184
185 #[test]
186 fn decrypt_long_ciphertext() {
187 let sk = SecretKey::from_bytes(&[1u8; 32]).unwrap();
188 let kp = Keypair::from(sk.clone());
189
190 let mut point = kp.public().as_element().to_untagged_bytes().to_vec();
191 point.append(&mut point.clone());
192
193 let expected = vec![
194 172, 161, 83, 0, 40, 73, 212, 190, 29, 204, 157, 78, 217, 152, 216, 235, 155, 39, 228,
195 115, 176, 146, 44, 117, 228, 161, 45, 97, 177, 206, 222, 39, 112, 171, 121, 124, 145,
196 154, 37, 179, 108, 74, 77, 247, 132, 44, 68, 197, 162, 252, 131, 221, 46, 117, 145, 82,
197 33, 147, 21, 83, 103, 237, 70, 93,
198 ];
199
200 assert_eq!(decrypt(&sk, &point).unwrap(), expected);
201 point.append(&mut vec![1u8; 32]);
202 assert_eq!(decrypt(&sk, &point).unwrap(), expected);
203 }
204}