playready/crypto/
ecc_p256.rs1use elastic_elgamal::{group::Generic, Ciphertext};
2use p256::{
3 ecdsa::{
4 signature::{Signer, Verifier},
5 Signature, SigningKey, VerifyingKey,
6 },
7 elliptic_curve::sec1::{FromEncodedPoint, ToEncodedPoint},
8 AffinePoint, EncodedPoint, NistP256, ProjectivePoint,
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 let point = EncodedPoint::from_untagged_bytes(bytes.into());
60 let point = AffinePoint::from_encoded_point(&point)
61 .into_option()
62 .ok_or(crate::Error::P256DecodeError)?;
63
64 VerifyingKey::from_affine(point).or(Err(crate::Error::P256DecodeError))
65 }
66}
67
68pub fn wmrm_public_key() -> &'static PublicKey {
69 static CELL: OnceLock<PublicKey> = OnceLock::new();
70
71 CELL.get_or_init(|| {
72 const WMRM_KEY: [u8; 33] = [
73 0x02, 0xc8, 0xb6, 0xaf, 0x16, 0xee, 0x94, 0x1a, 0xad, 0xaa, 0x53, 0x89, 0xb4, 0xaf,
74 0x2c, 0x10, 0xe3, 0x56, 0xbe, 0x42, 0xaf, 0x17, 0x5e, 0xf3, 0xfa, 0xce, 0x93, 0x25,
75 0x4e, 0x7b, 0x0b, 0x3d, 0x9b,
76 ];
77
78 PublicKey::from_bytes(&WMRM_KEY).unwrap()
79 })
80}
81
82pub fn encrypt(public_key: &PublicKey, plaintext: ProjectivePoint) -> Vec<u8> {
83 let mut rng = rand::thread_rng();
84 let ciphertext = public_key.encrypt_element(plaintext, &mut rng);
85
86 let point1 = ciphertext.random_element().to_untagged_bytes();
87 let point2 = ciphertext.blinded_element().to_untagged_bytes();
88
89 [point1, point2].concat()
90}
91
92pub fn decrypt(private_key: &SecretKey, ciphertext: &[u8]) -> Result<Vec<u8>, crate::Error> {
93 let random_element = EncodedPoint::from_untagged_bytes(
94 ciphertext
95 .get(..64)
96 .ok_or(crate::Error::SliceOutOfBoundsError(
97 "ciphertext",
98 ciphertext.len(),
99 ))?
100 .into(),
101 );
102 let random_element = AffinePoint::from_encoded_point(&random_element)
103 .into_option()
104 .ok_or(crate::Error::P256DecodeError)?;
105
106 let blinded_element = EncodedPoint::from_untagged_bytes(
107 ciphertext
108 .get(64..)
109 .ok_or(crate::Error::SliceOutOfBoundsError(
110 "ciphertext",
111 ciphertext.len(),
112 ))?
113 .into(),
114 );
115 let blinded_element = AffinePoint::from_encoded_point(&blinded_element)
116 .into_option()
117 .ok_or(crate::Error::P256DecodeError)?;
118
119 let encrypted: Ciphertext<Generic<NistP256>> = Ciphertext::zero();
120
121 unsafe {
123 copy_nonoverlapping(
124 &random_element.into(),
125 encrypted.random_element() as *const ProjectivePoint as *mut ProjectivePoint,
126 1,
127 );
128 copy_nonoverlapping(
129 &blinded_element.into(),
130 encrypted.blinded_element() as *const ProjectivePoint as *mut ProjectivePoint,
131 1,
132 );
133 };
134
135 Ok(private_key
136 .decrypt_to_element(encrypted)
137 .to_untagged_bytes()
138 .to_vec())
139}
140
141pub fn verify(
142 verifying_key: &VerifyingKey,
143 msg: &[u8],
144 signature: &[u8],
145) -> Result<(), p256::ecdsa::Error> {
146 let signature = Signature::from_slice(signature)?;
147 verifying_key.verify(msg, &signature)
148}
149
150pub fn sign(signing_key: &SigningKey, msg: &[u8]) -> Vec<u8> {
151 let signature: Signature = signing_key.sign(msg);
152 signature.to_bytes().to_vec()
153}