diff --git a/Cargo.toml b/Cargo.toml index f01e5a553..249d12aa1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,4 +32,5 @@ proptest = "1.0" rand = "0.8" rand_chacha = "0.3" rand_core = "0.6" +serde = { version = "1.0", default-features = false, features = ["derive", "alloc"] } serde_json = "1.0" diff --git a/crypto/tecdsa/cait_sith_keplr/src/tests/test2.rs b/crypto/tecdsa/cait_sith_keplr/src/tests/test2.rs index 90716dafd..a05d9ce68 100644 --- a/crypto/tecdsa/cait_sith_keplr/src/tests/test2.rs +++ b/crypto/tecdsa/cait_sith_keplr/src/tests/test2.rs @@ -13,13 +13,18 @@ use crate::{ #[test] fn test_e2e_3() { - let participants = vec![Participant::from(0u32), Participant::from(1u32)]; + let participants = vec![ + Participant::from(0u32), + Participant::from(1u32), + Participant::from(2u32), + ]; let threshold = 2; println!("participants: {:#?}", participants); let keygen_result = keygen_2::(&participants, threshold).unwrap(); + // NOTE: we have 3 participants, but we only use 2 let triples_participants = vec![Participant::from(0u32), Participant::from(1u32)]; let triples_result = generate_triples_3::(&triples_participants, threshold).unwrap(); diff --git a/crypto/teddsa/frost_ed25519_keplr/Cargo.toml b/crypto/teddsa/frost_ed25519_keplr/Cargo.toml index 2c52b05fd..a337d6291 100644 --- a/crypto/teddsa/frost_ed25519_keplr/Cargo.toml +++ b/crypto/teddsa/frost_ed25519_keplr/Cargo.toml @@ -26,6 +26,7 @@ frost_core = { workspace = true } curve25519-dalek = { version = "=4.1.3", features = ["rand_core"] } document-features = { workspace = true } rand_core = { workspace = true } +serde = { workspace = true, optional = true } sha2 = { version = "0.10.2", default-features = false } [dev-dependencies] @@ -50,7 +51,7 @@ std = [] ## Enable `serde` support for types that need to be communicated. You ## can use `serde` to serialize structs with any encoder that supports ## `serde` (e.g. JSON with `serde_json`). -serde = ["frost_core/serde"] +serde = ["dep:serde", "frost_core/serde"] ## Enable a default serialization format. Enables `serde`. serialization = [ "serde", diff --git a/crypto/teddsa/frost_ed25519_keplr/src/point.rs b/crypto/teddsa/frost_ed25519_keplr/src/point.rs index ce305887a..189cfa549 100644 --- a/crypto/teddsa/frost_ed25519_keplr/src/point.rs +++ b/crypto/teddsa/frost_ed25519_keplr/src/point.rs @@ -4,6 +4,7 @@ use curve25519_dalek::scalar::Scalar; /// A 256-bit point with x and y coordinates. #[derive(Clone, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Point256 { /// X coordinate (32 bytes) pub x: [u8; 32], diff --git a/crypto/teddsa/frost_ed25519_keplr/src/sss/mod.rs b/crypto/teddsa/frost_ed25519_keplr/src/sss/mod.rs index 209d45f32..2cabcac6b 100644 --- a/crypto/teddsa/frost_ed25519_keplr/src/sss/mod.rs +++ b/crypto/teddsa/frost_ed25519_keplr/src/sss/mod.rs @@ -1,9 +1,11 @@ mod combine; mod lagrange; +mod reshare; mod split; pub use combine::*; pub use lagrange::*; +pub use reshare::*; pub use split::*; #[cfg(test)] diff --git a/crypto/teddsa/frost_ed25519_keplr/src/sss/reshare.rs b/crypto/teddsa/frost_ed25519_keplr/src/sss/reshare.rs new file mode 100644 index 000000000..ce08f9b4b --- /dev/null +++ b/crypto/teddsa/frost_ed25519_keplr/src/sss/reshare.rs @@ -0,0 +1,206 @@ +use alloc::collections::BTreeSet; +use alloc::format; +use alloc::string::{String, ToString}; +use alloc::vec::Vec; + +use frost_core::{Scalar, SigningKey}; +use rand_core::{CryptoRng, RngCore}; + +use crate::keys::{split, IdentifierList}; +use crate::point::Point256; +use crate::sss::compute_lagrange_coefficient; +use crate::{Ed25519Sha512, Identifier}; + +/// Result of a reshare operation. +#[derive(Debug, Clone, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct ReshareResult { + /// Threshold value (minimum shares required to reconstruct). + pub t: u32, + /// The reshared points for each node. + pub reshared_points: Vec, + /// The recovered secret. + pub secret: [u8; 32], +} + +/// Reshares existing keyshares to a new set of nodes with a fresh polynomial. +/// +/// This function recovers the secret from existing shares and creates new shares +/// for a potentially different set of nodes using a new random polynomial. +pub fn reshare( + split_points: Vec, + new_ks_node_hashes: Vec<[u8; 32]>, + t: u32, + rng: &mut R, +) -> Result { + if split_points.len() < t as usize { + return Err("Split points must be greater than t".to_string()); + } + + if new_ks_node_hashes.len() < t as usize { + return Err("New KS node hashes must be greater than t".to_string()); + } + + // Take first t points for interpolation + let truncated_points = split_points.iter().take(t as usize).collect::>(); + + // Build identifier set from x coordinates + let identifiers = truncated_points + .iter() + .map(|p| { + Identifier::deserialize(p.x.as_slice()) + .map_err(|e| format!("Failed to deserialize identifier: {:?}", e)) + }) + .collect::, String>>()?; + + // Compute Lagrange coefficients and interpolate to recover secret + let coeffs = identifiers + .iter() + .map(|id| { + compute_lagrange_coefficient::(&identifiers, None, *id) + .map_err(|e| format!("Failed to compute lagrange coefficient: {:?}", e)) + }) + .collect::, String>>()?; + + let mut secret_scalar = Scalar::::ZERO; + for (i, coeff) in coeffs.iter().enumerate() { + let y_scalar = SigningKey::::deserialize(truncated_points[i].y.as_slice()) + .map_err(|e| format!("Failed to deserialize signing key: {:?}", e))? + .to_scalar(); + secret_scalar = secret_scalar + *coeff * y_scalar; + } + + let secret = secret_scalar.to_bytes(); + + // Create new shares using fresh polynomial + let signing_key = SigningKey::::deserialize(secret.as_slice()) + .map_err(|e| format!("Failed to deserialize signing key: {:?}", e))?; + + let max_signers = new_ks_node_hashes.len() as u16; + let min_signers = t as u16; + + let new_identifiers = new_ks_node_hashes + .iter() + .map(|&x| { + Identifier::deserialize(x.as_slice()) + .map_err(|e| format!("Failed to deserialize identifier: {:?}", e)) + }) + .collect::, String>>()?; + let identifier_list = IdentifierList::Custom(&new_identifiers); + + let share_map_tup = split(&signing_key, max_signers, min_signers, identifier_list, rng) + .map_err(|e| format!("Failed to split: {:?}", e))?; + let share_vec = share_map_tup.0.into_iter().collect::>(); + + let reshared_points: Vec = share_vec + .into_iter() + .map(|(identifier, share)| Point256 { + x: identifier.to_scalar().to_bytes(), + y: share.signing_share().to_scalar().to_bytes(), + }) + .collect(); + + Ok(ReshareResult { + t, + reshared_points, + secret, + }) +} + +/// Expands existing shares to include additional nodes without changing the polynomial. +/// +/// This function uses Lagrange interpolation to compute share values for new nodes +/// based on the existing shares, preserving the original polynomial. +pub fn expand_shares( + split_points: Vec, + additional_ks_node_hashes: Vec<[u8; 32]>, + t: u32, +) -> Result { + if split_points.len() < t as usize { + return Err("Split points must be greater than t".to_string()); + } + + // Check that new hashes are not already in split_points + for split_point in split_points.iter() { + for new_hash in additional_ks_node_hashes.iter() { + if split_point.x == *new_hash { + return Err("New hash is already included in split points".to_string()); + } + } + } + + // Take first t points for interpolation + let truncated_points = split_points.iter().take(t as usize).collect::>(); + + // Build identifier set from x coordinates + let identifiers = truncated_points + .iter() + .map(|p| { + Identifier::deserialize(p.x.as_slice()) + .map_err(|e| format!("Failed to deserialize identifier: {:?}", e)) + }) + .collect::, String>>()?; + + // Recover secret for result + let coeffs_at_zero = identifiers + .iter() + .map(|id| { + compute_lagrange_coefficient::(&identifiers, None, *id) + .map_err(|e| format!("Failed to compute lagrange coefficient: {:?}", e)) + }) + .collect::, String>>()?; + + let mut secret_scalar = Scalar::::ZERO; + for (i, coeff) in coeffs_at_zero.iter().enumerate() { + let y_scalar = SigningKey::::deserialize(truncated_points[i].y.as_slice()) + .map_err(|e| format!("Failed to deserialize signing key: {:?}", e))? + .to_scalar(); + secret_scalar = secret_scalar + *coeff * y_scalar; + } + let secret = secret_scalar.to_bytes(); + + // Compute new points using Lagrange interpolation at new x values + let new_points = additional_ks_node_hashes + .iter() + .map(|&new_hash| { + let x_identifier = Identifier::deserialize(new_hash.as_slice()) + .map_err(|e| format!("Failed to deserialize identifier: {:?}", e))?; + + // Compute Lagrange coefficients at the new x value + let coeffs_at_x = identifiers + .iter() + .map(|id| { + compute_lagrange_coefficient::( + &identifiers, + Some(x_identifier), + *id, + ) + .map_err(|e| format!("Failed to compute lagrange coefficient: {:?}", e)) + }) + .collect::, String>>()?; + + // Interpolate y value + let mut y_scalar = Scalar::::ZERO; + for (i, coeff) in coeffs_at_x.iter().enumerate() { + let point_y_scalar = + SigningKey::::deserialize(truncated_points[i].y.as_slice()) + .map_err(|e| format!("Failed to deserialize signing key: {:?}", e))? + .to_scalar(); + y_scalar = y_scalar + *coeff * point_y_scalar; + } + + Ok(Point256 { + x: x_identifier.to_scalar().to_bytes(), + y: y_scalar.to_bytes(), + }) + }) + .collect::, String>>()?; + + let reshared_points = [split_points.clone(), new_points].concat(); + + Ok(ReshareResult { + t, + reshared_points, + secret, + }) +} diff --git a/crypto/teddsa/frost_ed25519_keplr/src/sss/tests.rs b/crypto/teddsa/frost_ed25519_keplr/src/sss/tests.rs index 8f08c498b..1fdfe5d37 100644 --- a/crypto/teddsa/frost_ed25519_keplr/src/sss/tests.rs +++ b/crypto/teddsa/frost_ed25519_keplr/src/sss/tests.rs @@ -1,10 +1,30 @@ use alloc::vec; use rand_core::OsRng; -use crate::sss::{sss_combine_ed25519, sss_split_ed25519}; +use crate::sss::{expand_shares, reshare, sss_combine_ed25519, sss_split_ed25519}; #[test] fn test_sss_combine_ed25519() { + let mut secret = [0; 32]; + secret[0] = 1; + + let mut point_1 = [0; 32]; + point_1[0] = 1; + let mut point_2 = [0; 32]; + point_2[0] = 2; + let mut point_3 = [0; 32]; + point_3[0] = 3; + + let mut rng = OsRng; + + let point_xs = vec![point_1, point_2, point_3]; + let split_points = sss_split_ed25519(secret, point_xs, 2, &mut rng).unwrap(); + let combined_secret = sss_combine_ed25519(split_points, 2).unwrap(); + assert_eq!(combined_secret, secret); +} + +#[test] +fn test_reshare() { let mut secret = [0; 32]; secret[31] = 1; @@ -19,6 +39,170 @@ fn test_sss_combine_ed25519() { let point_xs = vec![point_1, point_2, point_3]; let split_points = sss_split_ed25519(secret, point_xs, 2, &mut rng).unwrap(); - let combined_secret = sss_combine_ed25519(split_points, 2).unwrap(); + + // Reshare to new nodes + let mut new_point_1 = [0; 32]; + new_point_1[31] = 4; + let mut new_point_2 = [0; 32]; + new_point_2[31] = 5; + let mut new_point_3 = [0; 32]; + new_point_3[31] = 6; + + let new_ks_node_hashes = vec![new_point_1, new_point_2, new_point_3]; + let reshare_result = reshare(split_points, new_ks_node_hashes, 2, &mut rng).unwrap(); + + // Verify reshared secret matches original + assert_eq!(reshare_result.secret, secret); + assert_eq!(reshare_result.t, 2); + assert_eq!(reshare_result.reshared_points.len(), 3); + + // Verify we can combine the reshared points to recover secret + let combined_secret = sss_combine_ed25519(reshare_result.reshared_points, 2).unwrap(); assert_eq!(combined_secret, secret); } + +#[test] +fn test_expand_shares() { + let mut secret = [0; 32]; + secret[0] = 1; + + let mut point_1 = [0; 32]; + point_1[0] = 1; + let mut point_2 = [0; 32]; + point_2[0] = 2; + let mut point_3 = [0; 32]; + point_3[0] = 3; + + let mut rng = OsRng; + + let point_xs = vec![point_1, point_2, point_3]; + let split_points = sss_split_ed25519(secret, point_xs, 2, &mut rng).unwrap(); + + // Expand with additional nodes + let mut new_point_1 = [0; 32]; + new_point_1[0] = 4; + let mut new_point_2 = [0; 32]; + new_point_2[0] = 5; + + let additional_hashes = vec![new_point_1, new_point_2]; + let expand_result = expand_shares(split_points.clone(), additional_hashes, 2).unwrap(); + + // Verify secret is recovered correctly + assert_eq!(expand_result.secret, secret); + assert_eq!(expand_result.t, 2); + // Original 3 points + 2 new points = 5 + assert_eq!(expand_result.reshared_points.len(), 5); + + // Verify we can combine any 2 of the expanded points to recover secret + // Use new points only + let new_points_only = expand_result.reshared_points[3..].to_vec(); + let combined_from_new = sss_combine_ed25519(new_points_only, 2).unwrap(); + assert_eq!(combined_from_new, secret); + + // Use mix of old and new + let mixed_points = vec![ + expand_result.reshared_points[0].clone(), + expand_result.reshared_points[4].clone(), + ]; + let combined_from_mixed = sss_combine_ed25519(mixed_points, 2).unwrap(); + assert_eq!(combined_from_mixed, secret); +} + +#[test] +fn test_expand_shares_duplicate_error() { + let mut secret = [0; 32]; + secret[31] = 1; + + let mut point_1 = [0; 32]; + point_1[31] = 1; + let mut point_2 = [0; 32]; + point_2[31] = 2; + let mut point_3 = [0; 32]; + point_3[31] = 3; + + let mut rng = OsRng; + + let point_xs = vec![point_1, point_2, point_3]; + let split_points = sss_split_ed25519(secret, point_xs, 2, &mut rng).unwrap(); + + // Try to expand with a hash that's already in split_points + let duplicate_hash = split_points[0].x; + let additional_hashes = vec![duplicate_hash]; + let result = expand_shares(split_points, additional_hashes, 2); + + assert!(result.is_err()); + assert_eq!( + result.err().unwrap(), + "New hash is already included in split points" + ); +} + +#[test] +fn test_expand_shares_preserves_original_points_order() { + let mut secret = [0; 32]; + secret[0] = 1; + + let mut point_1 = [0; 32]; + point_1[0] = 1; + let mut point_2 = [0; 32]; + point_2[0] = 2; + let mut point_3 = [0; 32]; + point_3[0] = 3; + + let mut rng = OsRng; + + let point_xs = vec![point_1, point_2, point_3]; + let split_points = sss_split_ed25519(secret, point_xs, 2, &mut rng).unwrap(); + + // Expand with additional nodes + let mut new_point_1 = [0; 32]; + new_point_1[0] = 4; + let mut new_point_2 = [0; 32]; + new_point_2[0] = 5; + + let additional_hashes = vec![new_point_1, new_point_2]; + let expand_result = expand_shares(split_points.clone(), additional_hashes, 2).unwrap(); + + // Verify original points are preserved in order at the beginning + for (i, original_point) in split_points.iter().enumerate() { + assert_eq!( + expand_result.reshared_points[i].x, original_point.x, + "Original point {} x coordinate mismatch", + i + ); + assert_eq!( + expand_result.reshared_points[i].y, original_point.y, + "Original point {} y coordinate mismatch", + i + ); + } + + // Verify the structure: first 3 are original, last 2 are new + assert_eq!(expand_result.reshared_points.len(), 5); + assert_eq!(expand_result.reshared_points[0], split_points[0]); + assert_eq!(expand_result.reshared_points[1], split_points[1]); + assert_eq!(expand_result.reshared_points[2], split_points[2]); + + // Verify new points have unique x values different from all other points + let new_points = &expand_result.reshared_points[3..]; + for (i, new_point) in new_points.iter().enumerate() { + // Check against original points + for (j, original_point) in split_points.iter().enumerate() { + assert_ne!( + new_point.x, original_point.x, + "New point {} has same x as original point {}", + i, j + ); + } + // Check against other new points + for (j, other_new_point) in new_points.iter().enumerate() { + if i != j { + assert_ne!( + new_point.x, other_new_point.x, + "New point {} has same x as new point {}", + i, j + ); + } + } + } +} diff --git a/crypto/teddsa/frost_ed25519_keplr/tests/common_traits_tests.rs b/crypto/teddsa/frost_ed25519_keplr/tests/common_traits_tests.rs index db173929b..94a76a166 100644 --- a/crypto/teddsa/frost_ed25519_keplr/tests/common_traits_tests.rs +++ b/crypto/teddsa/frost_ed25519_keplr/tests/common_traits_tests.rs @@ -2,7 +2,7 @@ mod helpers; -use frost_ed25519::SigningKey; +use frost_ed25519_keplr::SigningKey; use helpers::samples; #[allow(clippy::unnecessary_literal_unwrap)] diff --git a/crypto/teddsa/frost_ed25519_keplr/tests/helpers/mod.rs b/crypto/teddsa/frost_ed25519_keplr/tests/helpers/mod.rs index 2a936ac3e..7d3ad1dd4 100644 --- a/crypto/teddsa/frost_ed25519_keplr/tests/helpers/mod.rs +++ b/crypto/teddsa/frost_ed25519_keplr/tests/helpers/mod.rs @@ -5,7 +5,7 @@ pub mod samples; use ed25519_dalek::Verifier; -use frost_ed25519::*; +use frost_ed25519_keplr::*; // #[cfg(test)] pub fn verify_signature( diff --git a/crypto/teddsa/frost_ed25519_keplr/tests/helpers/samples.rs b/crypto/teddsa/frost_ed25519_keplr/tests/helpers/samples.rs index e1d87e169..36a6fc466 100644 --- a/crypto/teddsa/frost_ed25519_keplr/tests/helpers/samples.rs +++ b/crypto/teddsa/frost_ed25519_keplr/tests/helpers/samples.rs @@ -3,7 +3,7 @@ use std::collections::BTreeMap; use frost_core::{round1::Nonce, Ciphersuite, Element, Group, Scalar}; -use frost_ed25519::{ +use frost_ed25519_keplr::{ keys::{ dkg::{round1, round2}, KeyPackage, PublicKeyPackage, SecretShare, SigningShare, VerifiableSecretSharingCommitment, @@ -14,7 +14,7 @@ use frost_ed25519::{ Field, Signature, SigningPackage, VerifyingKey, }; -type C = frost_ed25519::Ed25519Sha512; +type C = frost_ed25519_keplr::Ed25519Sha512; fn element1() -> Element { ::Group::generator() diff --git a/crypto/teddsa/frost_ed25519_keplr/tests/integration_tests.rs b/crypto/teddsa/frost_ed25519_keplr/tests/integration_tests.rs index 830f6457d..77bb73716 100644 --- a/crypto/teddsa/frost_ed25519_keplr/tests/integration_tests.rs +++ b/crypto/teddsa/frost_ed25519_keplr/tests/integration_tests.rs @@ -1,4 +1,4 @@ -use frost_ed25519::*; +use frost_ed25519_keplr::*; use lazy_static::lazy_static; use serde_json::Value; diff --git a/crypto/teddsa/frost_ed25519_keplr/tests/interoperability_tests.rs b/crypto/teddsa/frost_ed25519_keplr/tests/interoperability_tests.rs index e758ee248..cb0963849 100644 --- a/crypto/teddsa/frost_ed25519_keplr/tests/interoperability_tests.rs +++ b/crypto/teddsa/frost_ed25519_keplr/tests/interoperability_tests.rs @@ -1,5 +1,5 @@ use crate::Ed25519Sha512; -use frost_ed25519::*; +use frost_ed25519_keplr::*; mod helpers; diff --git a/crypto/teddsa/frost_ed25519_keplr/tests/recreation_tests.rs b/crypto/teddsa/frost_ed25519_keplr/tests/recreation_tests.rs index 5ae8964e4..e45ecc64f 100644 --- a/crypto/teddsa/frost_ed25519_keplr/tests/recreation_tests.rs +++ b/crypto/teddsa/frost_ed25519_keplr/tests/recreation_tests.rs @@ -1,7 +1,7 @@ //! Test for recreating packages from their components, which shows that they //! can be serialized and deserialized as the user wishes. -use frost_ed25519::{ +use frost_ed25519_keplr::{ keys::{ dkg::{round1, round2}, KeyPackage, PublicKeyPackage, SecretShare, diff --git a/crypto/teddsa/frost_ed25519_keplr/tests/rerandomized_tests.rs b/crypto/teddsa/frost_ed25519_keplr/tests/rerandomized_tests.rs index 121738744..2c13f8aa0 100644 --- a/crypto/teddsa/frost_ed25519_keplr/tests/rerandomized_tests.rs +++ b/crypto/teddsa/frost_ed25519_keplr/tests/rerandomized_tests.rs @@ -1,4 +1,4 @@ -use frost_ed25519::Ed25519Sha512; +use frost_ed25519_keplr::Ed25519Sha512; #[test] fn check_randomized_sign_with_dealer() { diff --git a/crypto/teddsa/frost_ed25519_keplr/tests/serde_tests.rs b/crypto/teddsa/frost_ed25519_keplr/tests/serde_tests.rs index 9f722797b..120d94df5 100644 --- a/crypto/teddsa/frost_ed25519_keplr/tests/serde_tests.rs +++ b/crypto/teddsa/frost_ed25519_keplr/tests/serde_tests.rs @@ -2,7 +2,7 @@ mod helpers; -use frost_ed25519::{ +use frost_ed25519_keplr::{ keys::{ dkg::{round1, round2}, KeyPackage, PublicKeyPackage, SecretShare, diff --git a/crypto/teddsa/frost_ed25519_keplr/tests/serialization_tests.rs b/crypto/teddsa/frost_ed25519_keplr/tests/serialization_tests.rs index 7fe52b912..7c8a001a9 100644 --- a/crypto/teddsa/frost_ed25519_keplr/tests/serialization_tests.rs +++ b/crypto/teddsa/frost_ed25519_keplr/tests/serialization_tests.rs @@ -2,7 +2,7 @@ mod helpers; -use frost_ed25519::{ +use frost_ed25519_keplr::{ keys::{ dkg::{round1, round2}, KeyPackage, PublicKeyPackage, SecretShare, diff --git a/crypto/teddsa/frost_ed25519_keplr_wasm/wasm/src/sss/combine.rs b/crypto/teddsa/frost_ed25519_keplr_wasm/wasm/src/sss/combine.rs index e51d568a7..5618809de 100644 --- a/crypto/teddsa/frost_ed25519_keplr_wasm/wasm/src/sss/combine.rs +++ b/crypto/teddsa/frost_ed25519_keplr_wasm/wasm/src/sss/combine.rs @@ -4,24 +4,11 @@ use wasm_bindgen::prelude::*; #[wasm_bindgen] pub fn sss_combine(points: JsValue, t: u32) -> Result { - let points_serde: Vec = points + let points: Vec = points .into_serde() .map_err(|err| JsValue::from_str(&err.to_string()))?; - // Convert to Point256 - let points: Vec = points_serde - .into_iter() - .map(|p| Point256 { x: p.x, y: p.y }) - .collect(); - - let out = - sss_combine_ed25519(points, t).map_err(|err| JsValue::from_str(&err.to_string()))?; + let out = sss_combine_ed25519(points, t).map_err(|err| JsValue::from_str(&err.to_string()))?; JsValue::from_serde(&out).map_err(|err| JsValue::from_str(&err.to_string())) } - -#[derive(serde::Serialize, serde::Deserialize)] -struct PointSerde { - x: [u8; 32], - y: [u8; 32], -} diff --git a/crypto/teddsa/frost_ed25519_keplr_wasm/wasm/src/sss/mod.rs b/crypto/teddsa/frost_ed25519_keplr_wasm/wasm/src/sss/mod.rs index fe99b1ad7..cb28634a6 100644 --- a/crypto/teddsa/frost_ed25519_keplr_wasm/wasm/src/sss/mod.rs +++ b/crypto/teddsa/frost_ed25519_keplr_wasm/wasm/src/sss/mod.rs @@ -1,5 +1,7 @@ mod combine; +mod reshare; mod split; pub use combine::*; +pub use reshare::*; pub use split::*; diff --git a/crypto/teddsa/frost_ed25519_keplr_wasm/wasm/src/sss/reshare.rs b/crypto/teddsa/frost_ed25519_keplr_wasm/wasm/src/sss/reshare.rs new file mode 100644 index 000000000..608cff373 --- /dev/null +++ b/crypto/teddsa/frost_ed25519_keplr_wasm/wasm/src/sss/reshare.rs @@ -0,0 +1,39 @@ +use frost_ed25519_keplr::{expand_shares, reshare, Point256, ReshareResult}; +use gloo_utils::format::JsValueSerdeExt; +use rand_core::OsRng; +use wasm_bindgen::prelude::*; + +#[wasm_bindgen] +pub fn sss_reshare(points: JsValue, ks_node_hashes: JsValue, t: u32) -> Result { + let points: Vec = points + .into_serde() + .map_err(|err| JsValue::from_str(&err.to_string()))?; + let ks_node_hashes: Vec<[u8; 32]> = ks_node_hashes + .into_serde() + .map_err(|err| JsValue::from_str(&err.to_string()))?; + + let mut rng = OsRng; + let out: ReshareResult = reshare(points, ks_node_hashes, t, &mut rng) + .map_err(|err| JsValue::from_str(&err.to_string()))?; + + JsValue::from_serde(&out).map_err(|err| JsValue::from_str(&err.to_string())) +} + +#[wasm_bindgen] +pub fn sss_expand_shares( + points: JsValue, + additional_ks_node_hashes: JsValue, + t: u32, +) -> Result { + let points: Vec = points + .into_serde() + .map_err(|err| JsValue::from_str(&err.to_string()))?; + let additional_ks_node_hashes: Vec<[u8; 32]> = additional_ks_node_hashes + .into_serde() + .map_err(|err| JsValue::from_str(&err.to_string()))?; + + let out: ReshareResult = expand_shares(points, additional_ks_node_hashes, t) + .map_err(|err| JsValue::from_str(&err.to_string()))?; + + JsValue::from_serde(&out).map_err(|err| JsValue::from_str(&err.to_string())) +} diff --git a/crypto/teddsa/frost_ed25519_keplr_wasm/wasm/src/sss/split.rs b/crypto/teddsa/frost_ed25519_keplr_wasm/wasm/src/sss/split.rs index f666b601a..b4a278928 100644 --- a/crypto/teddsa/frost_ed25519_keplr_wasm/wasm/src/sss/split.rs +++ b/crypto/teddsa/frost_ed25519_keplr_wasm/wasm/src/sss/split.rs @@ -1,4 +1,4 @@ -use frost_ed25519_keplr::sss_split_ed25519; +use frost_ed25519_keplr::{sss_split_ed25519, Point256}; use gloo_utils::format::JsValueSerdeExt; use rand_core::OsRng; use wasm_bindgen::prelude::*; @@ -13,20 +13,8 @@ pub fn sss_split(secret: JsValue, point_xs: JsValue, t: u32) -> Result = sss_split_ed25519(secret, point_xs, t, &mut rng) .map_err(|err| JsValue::from_str(&err.to_string()))?; - // Convert Point256 to serializable format - let serializable_out: Vec = out - .into_iter() - .map(|p| PointSerde { x: p.x, y: p.y }) - .collect(); - - JsValue::from_serde(&serializable_out).map_err(|err| JsValue::from_str(&err.to_string())) -} - -#[derive(serde::Serialize, serde::Deserialize)] -struct PointSerde { - x: [u8; 32], - y: [u8; 32], + JsValue::from_serde(&out).map_err(|err| JsValue::from_str(&err.to_string())) }