1use crate::{SdkError, SdkResult};
4use ecdsa::{
5 EncodedPoint, RecoveryId,
6 hazmat::{DigestPrimitive, VerifyPrimitive},
7 signature::hazmat::PrehashVerifier,
8};
9use elliptic_curve_tools::{group, prime_field};
10use lit_node_core::{
11 CompressedBytes, CompressedHex, CurveType, EcdsaSignedMessageShare, KeyFormatPreference,
12 PeerId, SignableOutput, SigningAlgorithm, SigningScheme,
13 hd_keys_curves_wasm::{HDDerivable, HDDeriver},
14 lit_rust_crypto::{
15 blsful::{self, Bls12381G2Impl, PublicKey, Signature},
16 decaf377, ed448_goldilocks,
17 elliptic_curve::{
18 self, Curve, CurveArithmetic, Field, FieldBytesSize, PrimeCurve, ScalarPrimitive,
19 generic_array::ArrayLength,
20 ops::Reduce,
21 pkcs8::AssociatedOid,
22 point::{AffineCoordinates, DecompressPoint, PointCompression},
23 sec1::{FromEncodedPoint, ModulusSize, ToEncodedPoint},
24 },
25 group::GroupEncoding,
26 jubjub, k256, p256, p384, pallas, vsss_rs,
27 },
28};
29
30use lit_node_core::ethers::utils::keccak256;
31use serde::{Deserialize, Serialize, de::DeserializeOwned};
32use std::ops::Add;
33
34#[derive(Debug, Clone, Serialize, Deserialize)]
36pub struct EcdsaSignatureShare<C>
37where
38 C: PrimeCurve + CurveArithmetic + DigestPrimitive,
39 C::ProjectivePoint: GroupEncoding,
40 C::Scalar: HDDeriver,
41 <FieldBytesSize<C> as Add>::Output: ArrayLength<u8>,
42{
43 #[serde(with = "group")]
45 pub r: C::ProjectivePoint,
46 #[serde(with = "prime_field")]
48 pub s: C::Scalar,
49}
50
51impl<C> EcdsaSignatureShare<C>
52where
53 C: PrimeCurve + CurveArithmetic + DigestPrimitive,
54 C::ProjectivePoint: GroupEncoding,
55 C::Scalar: HDDeriver,
56 <FieldBytesSize<C> as Add>::Output: ArrayLength<u8>,
57{
58 pub fn combine_into_signature(
61 shares: &[EcdsaSignatureShare<C>],
62 ) -> SdkResult<EcdsaFullSignature<C>> {
63 if shares.is_empty() {
65 return Err(SdkError::SignatureCombine(
66 "No shares were supplied".to_string(),
67 ));
68 }
69 if shares[1..].iter().any(|s| s.r != shares[0].r) {
71 return Err(SdkError::SignatureCombine(
72 "Incompatible signature shares".to_string(),
73 ));
74 }
75 let sig_s = shares.iter().fold(C::Scalar::ZERO, |acc, s| acc + s.s);
76
77 Ok(EcdsaFullSignature {
78 r: shares[0].r,
79 s: sig_s,
80 })
81 }
82}
83
84#[derive(Debug, Clone, Serialize, Deserialize)]
86pub struct EcdsaFullSignature<C>
87where
88 C: PrimeCurve + CurveArithmetic + DigestPrimitive,
89 C::ProjectivePoint: GroupEncoding,
90 C::Scalar: HDDeriver,
91 <FieldBytesSize<C> as Add>::Output: ArrayLength<u8>,
92{
93 #[serde(with = "group")]
95 pub r: C::ProjectivePoint,
96 #[serde(with = "prime_field")]
98 pub s: C::Scalar,
99}
100
101impl<C> TryFrom<EcdsaFullSignature<C>> for ecdsa::Signature<C>
102where
103 C: PrimeCurve + CurveArithmetic + DigestPrimitive,
104 C::ProjectivePoint: GroupEncoding,
105 C::Scalar: HDDeriver,
106 <FieldBytesSize<C> as Add>::Output: ArrayLength<u8>,
107{
108 type Error = SdkError;
109
110 fn try_from(value: EcdsaFullSignature<C>) -> SdkResult<Self> {
111 let r = x_coordinate::<C>(&value.r);
112 let r = <C::Scalar as Into<ScalarPrimitive<C>>>::into(r);
113 let s = <C::Scalar as Into<ScalarPrimitive<C>>>::into(value.s);
114 let signature = ecdsa::Signature::<C>::from_scalars(r.to_bytes(), s.to_bytes())?;
116 match signature.normalize_s() {
117 Some(normalized) => Ok(normalized),
118 None => Ok(signature),
119 }
120 }
121}
122
123#[derive(Clone, Debug, Serialize, Deserialize)]
125pub struct SignedDataOutput {
126 pub signature: String,
128 pub verifying_key: String,
130 pub signed_data: String,
132 pub recovery_id: Option<u8>,
134}
135
136pub fn combine_and_verify_signature_shares(
147 signature_shares: &[SignableOutput],
148) -> SdkResult<SignedDataOutput> {
149 let mut bls_signing_package = Vec::with_capacity(signature_shares.len());
150 let mut frost_signing_package = Vec::with_capacity(signature_shares.len());
151 let mut ecdsa_signing_package =
152 Vec::<EcdsaSignedMessageShare>::with_capacity(signature_shares.len());
153
154 for signature_share in signature_shares {
155 match signature_share {
156 SignableOutput::EcdsaSignedMessageShare(ecdsa_msg_share) => {
157 if ecdsa_msg_share.result == "success" {
158 ecdsa_signing_package.push(ecdsa_msg_share.clone());
159 }
160 }
161 SignableOutput::BlsSignedMessageShare(bls_msg_share) => {
162 if bls_msg_share.result == "success" {
163 let identifier: blsful::inner_types::Scalar =
164 serde_json::from_str(&bls_msg_share.share_id)?;
165 let signature_share: blsful::SignatureShare<Bls12381G2Impl> =
166 serde_json::from_str(&bls_msg_share.signature_share)?;
167 let verifying_share: blsful::PublicKeyShare<Bls12381G2Impl> =
168 serde_json::from_str(&bls_msg_share.verifying_share)?;
169 let public_key: PublicKey<Bls12381G2Impl> =
170 serde_json::from_str(&bls_msg_share.public_key)?;
171 let message = hex::decode(&bls_msg_share.message)?;
172 bls_signing_package.push((
173 identifier,
174 signature_share,
175 verifying_share,
176 public_key,
177 message,
178 bls_msg_share.peer_id.clone(),
179 ));
180 }
181 }
182 SignableOutput::FrostSignedMessageShare(frost_msg_share) => {
183 if frost_msg_share.result == "success" {
184 let identifier: lit_frost::Identifier =
185 serde_json::from_str(&frost_msg_share.share_id)?;
186 let signature_share: lit_frost::SignatureShare =
187 serde_json::from_str(&frost_msg_share.signature_share)?;
188 let verifying_share: lit_frost::VerifyingShare =
189 serde_json::from_str(&frost_msg_share.verifying_share)?;
190 let public_key: lit_frost::VerifyingKey =
191 serde_json::from_str(&frost_msg_share.public_key)?;
192 let signing_commitments: lit_frost::SigningCommitments =
193 serde_json::from_str(&frost_msg_share.signing_commitments)?;
194 let signing_scheme = frost_msg_share.sig_type.parse::<SigningScheme>()?;
195 let scheme = signing_scheme_to_frost_scheme(signing_scheme)?;
196 let message = hex::decode(&frost_msg_share.message)?;
197 frost_signing_package.push((
198 identifier,
199 signature_share,
200 verifying_share,
201 public_key,
202 signing_commitments,
203 scheme,
204 message,
205 frost_msg_share.peer_id.clone(),
206 ));
207 }
208 }
209 }
210 }
211
212 if frost_signing_package.len() > 1 {
213 let first_entry = &frost_signing_package[0];
214 let mut signature_shares = Vec::with_capacity(frost_signing_package.len());
215 let mut verifying_shares = Vec::with_capacity(frost_signing_package.len());
216 let mut signing_commitments = Vec::with_capacity(frost_signing_package.len());
217
218 signature_shares.push((first_entry.0.clone(), first_entry.1.clone()));
219 verifying_shares.push((first_entry.0.clone(), first_entry.2.clone()));
220 signing_commitments.push((first_entry.0.clone(), first_entry.4.clone()));
221
222 for entry in &frost_signing_package[1..] {
223 debug_assert_eq!(
224 first_entry.3, entry.3,
225 "frost public keys do not match: {}, {}",
226 first_entry.2, entry.2
227 );
228 debug_assert_eq!(
229 first_entry.5, entry.5,
230 "frost signing schemes do not match: {}, {}",
231 first_entry.4, entry.4
232 );
233 debug_assert_eq!(
234 first_entry.6,
235 entry.6,
236 "frost messages do not match: {}, {}",
237 hex::encode(&first_entry.6),
238 hex::encode(&entry.6)
239 );
240 signature_shares.push((entry.0.clone(), entry.1.clone()));
241 verifying_shares.push((entry.0.clone(), entry.2.clone()));
242 signing_commitments.push((entry.0.clone(), entry.4.clone()));
243 }
244 let res = first_entry.5.aggregate(
245 &first_entry.6,
246 &signing_commitments,
247 &signature_shares,
248 &verifying_shares,
249 &first_entry.3,
250 );
251 return if res.is_err() {
252 let e = res.expect_err("frost signature from shares is invalid");
253 match e {
254 lit_frost::Error::Cheaters(cheaters) => {
255 let mut cheater_peer_ids = Vec::with_capacity(cheaters.len());
256 for cheater in cheaters {
257 let found = frost_signing_package
258 .iter()
259 .find(|p| p.0 == cheater)
260 .map(|cheater| cheater.7.clone());
261 if let Some(peer_id) = found {
262 cheater_peer_ids.push(peer_id);
263 }
264 }
265 Err(SdkError::SignatureCombine(format!(
266 "frost signature from shares is invalid. Invalid share peer ids: {}",
267 cheater_peer_ids.join(", ")
268 )))
269 }
270 _ => Err(SdkError::SignatureCombine(e.to_string())),
271 }
272 } else {
273 Ok(SignedDataOutput {
274 signature: serde_json::to_string(
275 &res.expect("frost signature from shares is valid"),
276 )?,
277 verifying_key: serde_json::to_string(&first_entry.3)?,
278 signed_data: hex::encode(&first_entry.6),
279 recovery_id: None,
280 })
281 };
282 }
283 if bls_signing_package.len() > 1 {
284 let first_entry = &bls_signing_package[0];
285 let mut signature_shares = Vec::with_capacity(bls_signing_package.len());
286 let mut verifying_shares = Vec::with_capacity(bls_signing_package.len());
287
288 signature_shares.push(first_entry.1);
289 verifying_shares.push((first_entry.0, first_entry.5.clone(), first_entry.2));
290 for entry in &bls_signing_package[1..] {
291 debug_assert_eq!(
292 first_entry.3, entry.3,
293 "bls public keys do not match: {}, {}",
294 first_entry.2, entry.2
295 );
296 debug_assert_eq!(
297 first_entry.4,
298 entry.4,
299 "bls messages do not match: {}, {}",
300 hex::encode(&first_entry.4),
301 hex::encode(&entry.4)
302 );
303 signature_shares.push(entry.1);
304 verifying_shares.push((entry.0, entry.5.clone(), entry.2));
305 }
306 let public_key = first_entry.3;
307 let signature = Signature::<Bls12381G2Impl>::from_shares(&signature_shares)
308 .expect("bls signature from shares");
309 if signature.verify(&public_key, &first_entry.4).is_err() {
310 let mut invalid_shares = Vec::with_capacity(signature_shares.len());
312 for (share, (_identifier, peer_id, verifier)) in
313 signature_shares.iter().zip(verifying_shares.iter())
314 {
315 if share.verify(verifier, &first_entry.4).is_err() {
316 invalid_shares.push(peer_id.clone());
317 }
318 }
319 return Err(SdkError::SignatureCombine(format!(
320 "bls signature from shares is invalid. Invalid share peer ids: {}",
321 invalid_shares.join(", ")
322 )));
323 }
324 return Ok(SignedDataOutput {
325 signature: serde_json::to_string(&signature)?,
326 verifying_key: public_key.0.to_compressed_hex(),
327 signed_data: hex::encode(&first_entry.4),
328 recovery_id: None,
329 });
330 }
331 if ecdsa_signing_package.len() > 1 {
332 let signing_scheme = ecdsa_signing_package[0].sig_type.parse::<SigningScheme>()?;
333 match signing_scheme {
334 SigningScheme::EcdsaK256Sha256 => {
335 return verify_ecdsa_signing_package::<k256::Secp256k1>(&ecdsa_signing_package);
336 }
337 SigningScheme::EcdsaP256Sha256 => {
338 return verify_ecdsa_signing_package::<p256::NistP256>(&ecdsa_signing_package);
339 }
340 SigningScheme::EcdsaP384Sha384 => {
341 return verify_ecdsa_signing_package::<p384::NistP384>(&ecdsa_signing_package);
342 }
343 _ => {}
344 }
345 }
346
347 Err(SdkError::SignatureCombine(
348 "no valid signature shares found".to_string(),
349 ))
350}
351
352pub fn verify_ecdsa_signing_package<C>(
354 shares: &[EcdsaSignedMessageShare],
355) -> SdkResult<SignedDataOutput>
356where
357 C: PrimeCurve + CurveArithmetic + DigestPrimitive + AssociatedOid + PointCompression,
358 C::ProjectivePoint: GroupEncoding + HDDerivable,
359 C::AffinePoint: DeserializeOwned
360 + FromEncodedPoint<C>
361 + ToEncodedPoint<C>
362 + VerifyPrimitive<C>
363 + DecompressPoint<C>,
364 C::Scalar: HDDeriver + From<PeerId> + DeserializeOwned,
365 <FieldBytesSize<C> as Add>::Output: ArrayLength<u8>,
366 <C as Curve>::FieldBytesSize: ModulusSize,
367{
368 let mut sig_shares = Vec::<EcdsaSignatureShare<C>>::with_capacity(shares.len());
369 let first_share = &shares[0];
370 sig_shares.push(EcdsaSignatureShare {
371 r: C::ProjectivePoint::from(serde_json::from_str::<C::AffinePoint>(&first_share.big_r)?),
372 s: serde_json::from_str(&first_share.signature_share)?,
373 });
374 for share in &shares[1..] {
375 debug_assert_eq!(first_share.public_key, share.public_key);
376 debug_assert_eq!(first_share.digest, share.digest);
377 debug_assert_eq!(first_share.big_r, share.big_r);
378 debug_assert_eq!(first_share.sig_type, share.sig_type);
379
380 sig_shares.push(EcdsaSignatureShare {
381 r: C::ProjectivePoint::from(serde_json::from_str::<C::AffinePoint>(&share.big_r)?),
382 s: serde_json::from_str(&share.signature_share)?,
383 });
384 }
385 let initial_public_key: String =
386 serde_json::from_str(&first_share.public_key).expect("public key");
387 let public_key = hex::decode(&initial_public_key)?;
388 let public_key = EncodedPoint::<C>::from_bytes(&public_key)
389 .map_err(|_| SdkError::SignatureCombine("invalid public key".to_string()))?;
390 let public_key_affine = Option::from(C::AffinePoint::from_encoded_point(&public_key))
391 .ok_or_else(|| SdkError::SignatureCombine("invalid public key".to_string()))?;
392 let signature =
393 EcdsaSignatureShare::<C>::combine_into_signature(&sig_shares).expect("signature");
394
395 let message = hex::decode(&first_share.digest)?;
396 let vk = ecdsa::VerifyingKey::<C>::from_affine(public_key_affine).expect("verifying key");
397 let signature: ecdsa::Signature<C> = signature.try_into().expect("signature");
398 <ecdsa::VerifyingKey<C> as PrehashVerifier<ecdsa::Signature<C>>>::verify_prehash(
399 &vk, &message, &signature,
400 )?;
401
402 let rid = RecoveryId::trial_recovery_from_prehash(&vk, &message, &signature)?;
403
404 Ok(SignedDataOutput {
405 signature: serde_json::to_string(&signature)?,
406 verifying_key: initial_public_key,
407 signed_data: shares[0].digest.clone(),
408 recovery_id: Some(rid.to_byte()),
409 })
410}
411
412pub fn verify_signature(
414 signing_scheme: SigningScheme,
415 package: &SignedDataOutput,
416) -> SdkResult<()> {
417 match signing_scheme {
418 SigningScheme::EcdsaK256Sha256 => verify_ecdsa_signature::<k256::Secp256k1>(package),
419 SigningScheme::EcdsaP256Sha256 => verify_ecdsa_signature::<p256::NistP256>(package),
420 SigningScheme::EcdsaP384Sha384 => verify_ecdsa_signature::<p384::NistP384>(package),
421 SigningScheme::SchnorrEd25519Sha512
422 | SigningScheme::SchnorrRistretto25519Sha512
423 | SigningScheme::SchnorrK256Sha256
424 | SigningScheme::SchnorrP256Sha256
425 | SigningScheme::SchnorrP384Sha384
426 | SigningScheme::SchnorrK256Taproot
427 | SigningScheme::SchnorrEd448Shake256
428 | SigningScheme::SchnorrRedJubjubBlake2b512
429 | SigningScheme::SchnorrRedPallasBlake2b512
430 | SigningScheme::SchnorrRedDecaf377Blake2b512
431 | SigningScheme::SchnorrkelSubstrate => {
432 let scheme = signing_scheme_to_frost_scheme(signing_scheme)?;
433 let signature = serde_json::from_str::<lit_frost::Signature>(&package.signature)?;
434 let public_key =
435 serde_json::from_str::<lit_frost::VerifyingKey>(&package.verifying_key)?;
436 let message = hex::decode(&package.signed_data)?;
437 scheme
438 .verify(&message, &public_key, &signature)
439 .map_err(|_| SdkError::SignatureVerify)
440 }
441 SigningScheme::Bls12381G1ProofOfPossession | SigningScheme::Bls12381 => {
442 let public_key: PublicKey<Bls12381G2Impl> =
443 serde_json::from_str(&format!("\"{}\"", &package.verifying_key))?;
444 let signature: Signature<Bls12381G2Impl> = serde_json::from_str(&package.signature)?;
445 let message = hex::decode(&package.signed_data)?;
446 signature.verify(&public_key, &message)?;
447 Ok(())
448 }
449 }
450}
451
452pub fn signing_scheme_to_frost_scheme(value: SigningScheme) -> SdkResult<lit_frost::Scheme> {
454 match value {
455 SigningScheme::Bls12381 | SigningScheme::Bls12381G1ProofOfPossession => Err(
456 SdkError::Parse("BLS signatures are not supported by FROST".to_string()),
457 ),
458 SigningScheme::EcdsaK256Sha256
459 | SigningScheme::EcdsaP256Sha256
460 | SigningScheme::EcdsaP384Sha384 => Err(SdkError::Parse(
461 "ECDSA signatures are not supported by FROST".to_string(),
462 )),
463 SigningScheme::SchnorrEd25519Sha512 => Ok(lit_frost::Scheme::Ed25519Sha512),
464 SigningScheme::SchnorrK256Sha256 => Ok(lit_frost::Scheme::K256Sha256),
465 SigningScheme::SchnorrP256Sha256 => Ok(lit_frost::Scheme::P256Sha256),
466 SigningScheme::SchnorrP384Sha384 => Ok(lit_frost::Scheme::P384Sha384),
467 SigningScheme::SchnorrRistretto25519Sha512 => Ok(lit_frost::Scheme::Ristretto25519Sha512),
468 SigningScheme::SchnorrEd448Shake256 => Ok(lit_frost::Scheme::Ed448Shake256),
469 SigningScheme::SchnorrRedJubjubBlake2b512 => Ok(lit_frost::Scheme::RedJubjubBlake2b512),
470 SigningScheme::SchnorrRedPallasBlake2b512 => Ok(lit_frost::Scheme::RedPallasBlake2b512),
471 SigningScheme::SchnorrK256Taproot => Ok(lit_frost::Scheme::K256Taproot),
472 SigningScheme::SchnorrRedDecaf377Blake2b512 => Ok(lit_frost::Scheme::RedDecaf377Blake2b512),
473 SigningScheme::SchnorrkelSubstrate => Ok(lit_frost::Scheme::SchnorrkelSubstrate),
474 }
475}
476
477pub fn verify_ecdsa_signature<C>(package: &SignedDataOutput) -> SdkResult<()>
479where
480 C: PrimeCurve + CurveArithmetic + DigestPrimitive + AssociatedOid + PointCompression,
481 C::ProjectivePoint: GroupEncoding + HDDerivable,
482 C::AffinePoint: DeserializeOwned
483 + FromEncodedPoint<C>
484 + ToEncodedPoint<C>
485 + VerifyPrimitive<C>
486 + DecompressPoint<C>,
487 C::Scalar: HDDeriver + From<PeerId> + DeserializeOwned,
488 <FieldBytesSize<C> as Add>::Output: ArrayLength<u8>,
489 <C as Curve>::FieldBytesSize: ModulusSize,
490{
491 let message = hex::decode(&package.signed_data)?;
492 let public_key = hex::decode(&package.verifying_key)?;
493 let public_key = EncodedPoint::<C>::from_bytes(&public_key)
494 .map_err(|_| SdkError::SignatureCombine("invalid public key".to_string()))?;
495 let public_key_affine = Option::from(C::AffinePoint::from_encoded_point(&public_key))
496 .ok_or_else(|| SdkError::SignatureCombine("invalid public key".to_string()))?;
497 let vk = ecdsa::VerifyingKey::<C>::from_affine(public_key_affine).expect("verifying key");
498 let signature = serde_json::from_str::<ecdsa::Signature<C>>(&package.signature)?;
499 <ecdsa::VerifyingKey<C> as PrehashVerifier<ecdsa::Signature<C>>>::verify_prehash(
500 &vk, &message, &signature,
501 )?;
502 Ok(())
503}
504
505pub(crate) fn x_coordinate<C>(point: &C::ProjectivePoint) -> C::Scalar
506where
507 C: PrimeCurve + CurveArithmetic,
508{
509 use elliptic_curve::group::Curve as _;
510
511 let pt = point.to_affine();
512 <C::Scalar as Reduce<<C as Curve>::Uint>>::reduce_bytes(&pt.x())
513}
514
515pub fn get_derived_public_key(
517 signing_scheme: SigningScheme,
518 key_id: &[u8],
519 root_keys: &[String],
520) -> SdkResult<String> {
521 match signing_scheme.curve_type() {
522 CurveType::BLS | CurveType::BLS12381G1 => derive_public_key::<
523 blsful::inner_types::G1Projective,
524 >(signing_scheme, key_id, root_keys),
525 CurveType::K256 => {
526 derive_public_key::<k256::ProjectivePoint>(signing_scheme, key_id, root_keys)
527 }
528 CurveType::P256 => {
529 derive_public_key::<p256::ProjectivePoint>(signing_scheme, key_id, root_keys)
530 }
531 CurveType::P384 => {
532 derive_public_key::<p384::ProjectivePoint>(signing_scheme, key_id, root_keys)
533 }
534 CurveType::Ed25519 => derive_public_key::<vsss_rs::curve25519::WrappedEdwards>(
535 signing_scheme,
536 key_id,
537 root_keys,
538 ),
539 CurveType::Ristretto25519 => derive_public_key::<vsss_rs::curve25519::WrappedRistretto>(
540 signing_scheme,
541 key_id,
542 root_keys,
543 ),
544 CurveType::Ed448 => {
545 derive_public_key::<ed448_goldilocks::EdwardsPoint>(signing_scheme, key_id, root_keys)
546 }
547 CurveType::RedJubjub => {
548 derive_public_key::<jubjub::SubgroupPoint>(signing_scheme, key_id, root_keys)
549 }
550 CurveType::RedPallas => {
551 derive_public_key::<pallas::Point>(signing_scheme, key_id, root_keys)
552 }
553 CurveType::RedDecaf377 => {
554 derive_public_key::<decaf377::Element>(signing_scheme, key_id, root_keys)
555 }
556 }
557}
558
559fn derive_public_key<G>(
560 signing_scheme: SigningScheme,
561 key_id: &[u8],
562 root_keys: &[String],
563) -> SdkResult<String>
564where
565 G: HDDerivable + GroupEncoding + Default + CompressedBytes,
566 G::Scalar: HDDeriver,
567{
568 let deriver = G::Scalar::create(key_id, signing_scheme.id_sign_ctx());
569 let mut keys = Vec::with_capacity(root_keys.len());
570 for rk in root_keys {
571 let rk = G::from_compressed_hex(rk)
572 .ok_or_else(|| SdkError::Parse("Invalid root key".to_string()))?;
573 keys.push(rk);
574 }
575 let pk = deriver.hd_derive_public_key(&keys);
576
577 if signing_scheme.supports_algorithm(SigningAlgorithm::Schnorr) {
578 let pk = lit_frost::VerifyingKey {
579 scheme: signing_scheme_to_frost_scheme(signing_scheme)?,
580 value: pk.to_compressed(),
581 };
582 let pk = serde_json::to_string(&pk)?;
583 Ok(pk)
584 } else {
585 Ok(match signing_scheme.preferred_format() {
586 KeyFormatPreference::Compressed => pk.to_compressed_hex(),
587 KeyFormatPreference::Uncompressed => pk.to_uncompressed_hex(),
588 })
589 }
590}
591
592pub fn get_lit_action_public_key(
594 signing_scheme: SigningScheme,
595 action_ipfs_id: &str,
596 root_keys: &[String],
597) -> SdkResult<String> {
598 let key_id = keccak256(format!("lit_action_{}", action_ipfs_id));
599 get_derived_public_key(signing_scheme, &key_id, root_keys)
600}