1use crate::SignatureError;
2use k256::ecdsa::SigningKey;
3use k256::ecdsa::VerifyingKey;
4use k256::elliptic_curve::group::GroupEncoding;
5use signature::Signer;
6use signature::Verifier;
7use sui_sdk_types::Secp256k1PublicKey;
8use sui_sdk_types::Secp256k1Signature;
9use sui_sdk_types::SignatureScheme;
10use sui_sdk_types::SimpleSignature;
11use sui_sdk_types::UserSignature;
12
13#[derive(Clone)]
14pub struct Secp256k1PrivateKey(SigningKey);
15
16impl std::fmt::Debug for Secp256k1PrivateKey {
17 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
18 f.debug_tuple("Secp256k1PrivateKey")
19 .field(&"__elided__")
20 .finish()
21 }
22}
23
24#[cfg(test)]
25impl proptest::arbitrary::Arbitrary for Secp256k1PrivateKey {
26 type Parameters = ();
27 type Strategy = proptest::strategy::BoxedStrategy<Self>;
28 fn arbitrary_with(_: Self::Parameters) -> Self::Strategy {
29 use proptest::strategy::Strategy;
30
31 proptest::arbitrary::any::<[u8; Self::LENGTH]>()
32 .prop_filter_map("invalid secp256k1 private key", |bytes| {
33 Self::new(bytes).ok()
34 })
35 .boxed()
36 }
37}
38
39impl Secp256k1PrivateKey {
40 pub const LENGTH: usize = 32;
42
43 pub fn new(bytes: [u8; Self::LENGTH]) -> Result<Self, SignatureError> {
44 SigningKey::from_bytes(&bytes.into()).map(Self)
45 }
46
47 pub fn scheme(&self) -> SignatureScheme {
48 SignatureScheme::Secp256k1
49 }
50
51 pub fn verifying_key(&self) -> Secp256k1VerifyingKey {
52 let verifying_key = self.0.verifying_key();
53 Secp256k1VerifyingKey(*verifying_key)
54 }
55
56 pub fn public_key(&self) -> Secp256k1PublicKey {
57 Secp256k1PublicKey::new(self.0.verifying_key().as_ref().to_bytes().into())
58 }
59
60 pub fn generate<R>(mut rng: R) -> Self
61 where
62 R: rand_core::RngCore + rand_core::CryptoRng,
63 {
64 Self(SigningKey::random(&mut rng))
65 }
66
67 #[cfg(feature = "pem")]
68 #[cfg_attr(doc_cfg, doc(cfg(feature = "pem")))]
69 pub fn from_der(bytes: &[u8]) -> Result<Self, SignatureError> {
71 k256::pkcs8::DecodePrivateKey::from_pkcs8_der(bytes)
72 .map(Self)
73 .map_err(SignatureError::from_source)
74 }
75
76 #[cfg(feature = "pem")]
77 #[cfg_attr(doc_cfg, doc(cfg(feature = "pem")))]
78 pub fn to_der(&self) -> Result<Vec<u8>, SignatureError> {
80 use k256::pkcs8::EncodePrivateKey;
81
82 self.0
83 .to_pkcs8_der()
84 .map_err(SignatureError::from_source)
85 .map(|der| der.as_bytes().to_owned())
86 }
87
88 #[cfg(feature = "pem")]
89 #[cfg_attr(doc_cfg, doc(cfg(feature = "pem")))]
90 pub fn from_pem(s: &str) -> Result<Self, SignatureError> {
92 k256::pkcs8::DecodePrivateKey::from_pkcs8_pem(s)
93 .map(Self)
94 .map_err(SignatureError::from_source)
95 }
96
97 #[cfg(feature = "pem")]
98 #[cfg_attr(doc_cfg, doc(cfg(feature = "pem")))]
99 pub fn to_pem(&self) -> Result<String, SignatureError> {
101 use pkcs8::EncodePrivateKey;
102
103 self.0
104 .to_pkcs8_pem(pkcs8::LineEnding::default())
105 .map_err(SignatureError::from_source)
106 .map(|pem| (*pem).to_owned())
107 }
108
109 #[cfg(feature = "pem")]
110 pub(crate) fn from_k256(private_key: SigningKey) -> Self {
111 Self(private_key)
112 }
113
114 #[cfg(feature = "bech32")]
115 #[cfg_attr(doc_cfg, doc(cfg(feature = "bech32")))]
116 pub fn from_suiprivkey(s: &str) -> Result<Self, SignatureError> {
123 let (scheme, key) = crate::suipriv::decode(s)?;
124 if scheme != SignatureScheme::Secp256k1 {
125 return Err(SignatureError::from_source(format!(
126 "suipriv scheme flag is `{}`, expected `secp256k1`",
127 scheme.name(),
128 )));
129 }
130 let bytes: [u8; Self::LENGTH] = key.try_into().map_err(|_: Vec<u8>| {
131 SignatureError::from_source("suipriv key has invalid length for secp256k1")
132 })?;
133 Self::new(bytes)
134 }
135
136 #[cfg(feature = "bech32")]
137 #[cfg_attr(doc_cfg, doc(cfg(feature = "bech32")))]
138 pub fn to_suiprivkey(&self) -> Result<String, SignatureError> {
140 let bytes = self.0.to_bytes();
141 crate::suipriv::encode(SignatureScheme::Secp256k1, &bytes)
142 }
143}
144
145impl Signer<Secp256k1Signature> for Secp256k1PrivateKey {
146 fn try_sign(&self, message: &[u8]) -> Result<Secp256k1Signature, SignatureError> {
147 let signature: k256::ecdsa::Signature = self.0.try_sign(message)?;
148 Ok(Secp256k1Signature::new(signature.to_bytes().into()))
149 }
150}
151
152impl Signer<SimpleSignature> for Secp256k1PrivateKey {
153 fn try_sign(&self, msg: &[u8]) -> Result<SimpleSignature, SignatureError> {
154 <Self as Signer<Secp256k1Signature>>::try_sign(self, msg).map(|signature| {
155 SimpleSignature::Secp256k1 {
156 signature,
157 public_key: self.public_key(),
158 }
159 })
160 }
161}
162
163impl Signer<UserSignature> for Secp256k1PrivateKey {
164 fn try_sign(&self, msg: &[u8]) -> Result<UserSignature, SignatureError> {
165 <Self as Signer<SimpleSignature>>::try_sign(self, msg).map(UserSignature::Simple)
166 }
167}
168
169#[derive(Debug, Clone, Eq, PartialEq)]
170pub struct Secp256k1VerifyingKey(VerifyingKey);
171
172impl Secp256k1VerifyingKey {
173 pub fn new(public_key: &Secp256k1PublicKey) -> Result<Self, SignatureError> {
174 VerifyingKey::try_from(public_key.inner().as_ref()).map(Self)
175 }
176
177 pub fn public_key(&self) -> Secp256k1PublicKey {
178 Secp256k1PublicKey::new(self.0.as_ref().to_bytes().into())
179 }
180
181 #[cfg(feature = "pem")]
182 #[cfg_attr(doc_cfg, doc(cfg(feature = "pem")))]
183 pub fn from_der(bytes: &[u8]) -> Result<Self, SignatureError> {
185 k256::pkcs8::DecodePublicKey::from_public_key_der(bytes)
186 .map(Self)
187 .map_err(SignatureError::from_source)
188 }
189
190 #[cfg(feature = "pem")]
191 #[cfg_attr(doc_cfg, doc(cfg(feature = "pem")))]
192 pub fn to_der(&self) -> Result<Vec<u8>, SignatureError> {
194 use pkcs8::EncodePublicKey;
195
196 self.0
197 .to_public_key_der()
198 .map_err(SignatureError::from_source)
199 .map(|der| der.into_vec())
200 }
201
202 #[cfg(feature = "pem")]
203 #[cfg_attr(doc_cfg, doc(cfg(feature = "pem")))]
204 pub fn from_pem(s: &str) -> Result<Self, SignatureError> {
206 k256::pkcs8::DecodePublicKey::from_public_key_pem(s)
207 .map(Self)
208 .map_err(SignatureError::from_source)
209 }
210
211 #[cfg(feature = "pem")]
212 #[cfg_attr(doc_cfg, doc(cfg(feature = "pem")))]
213 pub fn to_pem(&self) -> Result<String, SignatureError> {
215 use pkcs8::EncodePublicKey;
216
217 self.0
218 .to_public_key_pem(pkcs8::LineEnding::default())
219 .map_err(SignatureError::from_source)
220 }
221
222 #[cfg(feature = "pem")]
223 pub(crate) fn from_k256(verifying_key: VerifyingKey) -> Self {
224 Self(verifying_key)
225 }
226}
227
228impl Verifier<Secp256k1Signature> for Secp256k1VerifyingKey {
229 fn verify(&self, message: &[u8], signature: &Secp256k1Signature) -> Result<(), SignatureError> {
230 let signature = k256::ecdsa::Signature::from_bytes(signature.inner().into())?;
231 self.0.verify(message, &signature)
232 }
233}
234
235impl Verifier<SimpleSignature> for Secp256k1VerifyingKey {
236 fn verify(&self, message: &[u8], signature: &SimpleSignature) -> Result<(), SignatureError> {
237 let SimpleSignature::Secp256k1 {
238 signature,
239 public_key,
240 } = signature
241 else {
242 return Err(SignatureError::from_source("not a secp256k1 signature"));
243 };
244
245 if public_key.inner() != self.public_key().inner() {
246 return Err(SignatureError::from_source(
247 "public_key in signature does not match",
248 ));
249 }
250
251 <Self as Verifier<Secp256k1Signature>>::verify(self, message, signature)
252 }
253}
254
255impl Verifier<UserSignature> for Secp256k1VerifyingKey {
256 fn verify(&self, message: &[u8], signature: &UserSignature) -> Result<(), SignatureError> {
257 let UserSignature::Simple(signature) = signature else {
258 return Err(SignatureError::from_source("not a secp256k1 signature"));
259 };
260
261 <Self as Verifier<SimpleSignature>>::verify(self, message, signature)
262 }
263}
264
265#[derive(Default, Clone, Debug)]
266pub struct Secp256k1Verifier {}
267
268impl Secp256k1Verifier {
269 pub fn new() -> Self {
270 Self {}
271 }
272}
273
274impl Verifier<SimpleSignature> for Secp256k1Verifier {
275 fn verify(&self, message: &[u8], signature: &SimpleSignature) -> Result<(), SignatureError> {
276 let SimpleSignature::Secp256k1 {
277 signature,
278 public_key,
279 } = signature
280 else {
281 return Err(SignatureError::from_source("not a secp256k1 signature"));
282 };
283
284 let verifying_key = Secp256k1VerifyingKey::new(public_key)?;
285
286 verifying_key.verify(message, signature)
287 }
288}
289
290impl Verifier<UserSignature> for Secp256k1Verifier {
291 fn verify(&self, message: &[u8], signature: &UserSignature) -> Result<(), SignatureError> {
292 let UserSignature::Simple(signature) = signature else {
293 return Err(SignatureError::from_source("not a secp256k1 signature"));
294 };
295
296 <Self as Verifier<SimpleSignature>>::verify(self, message, signature)
297 }
298}
299
300#[cfg(test)]
301mod test {
302 use super::*;
303 use crate::SuiSigner;
304 use crate::SuiVerifier;
305 use sui_sdk_types::PersonalMessage;
306 use test_strategy::proptest;
307
308 #[cfg(target_arch = "wasm32")]
309 use wasm_bindgen_test::wasm_bindgen_test as test;
310
311 #[proptest]
322 fn personal_message_signing(signer: Secp256k1PrivateKey, message: Vec<u8>) {
323 let message = PersonalMessage(message.into());
324 let signature = signer.sign_personal_message(&message).unwrap();
325 let verifying_key = signer.verifying_key();
326 verifying_key
327 .verify_personal_message(&message, &signature)
328 .unwrap();
329
330 let verifier = Secp256k1Verifier::default();
331 verifier
332 .verify_personal_message(&message, &signature)
333 .unwrap();
334 }
335
336 #[test]
337 fn personal_message_signing_fixture() {
338 let key = [
339 172, 12, 96, 180, 207, 143, 111, 151, 81, 57, 242, 89, 74, 5, 150, 51, 56, 111, 245,
340 150, 182, 30, 149, 178, 29, 255, 188, 27, 48, 241, 151, 193,
341 ];
342
343 let signer = Secp256k1PrivateKey::new(key).unwrap();
344
345 let message = PersonalMessage(b"hello".into());
346 let sig = signer.sign_personal_message(&message).unwrap();
347 let external_sig = "AVFAWGjuD8+xUoc6jMC0lKqMtT+4ukln7vz+8Nuv+EbYKl47jwzOWn39maDsqu81kezLPgLzz6o/AfSE0M9+jVwClcrtiuyUggEt/6CEZi8+JQ+NS9TmOhPBZV2X1KjhGCw=";
348 let b64 = sig.to_base64();
349 assert_eq!(external_sig, b64);
350 }
351}