Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
102 changes: 1 addition & 101 deletions common/oko_types/src/user_key_share/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Bytes, type Bytes32, type Bytes64 } from "@oko-wallet/bytes";
import type { Bytes32 } from "@oko-wallet/bytes";

export interface RunExpandSharesResult {
t: number;
Expand All @@ -24,103 +24,3 @@ export interface PointNumArr {
x: number[];
y: number[];
}

/**
* TEDDSA key share for KS Node storage.
*
* identifier: 32 bytes - SSS x-coordinate (node_name SHA256, byte[31] &= 0x0F)
* signing_share: 32 bytes - SSS y-coordinate (split signing share)
*
* Note: verifying_share is NOT stored.
* It can be recovered from signing_share via scalar_base_mult().
*
* Total: 64 bytes (same size as Point256)
*/
export interface TeddsaKeyShare {
identifier: Bytes32;
signing_share: Bytes32;
}

export interface TeddsaKeyShareByNode {
node: NodeNameAndEndpoint;
share: TeddsaKeyShare;
}

/**
* Serialize TeddsaKeyShare to Bytes64.
* Format: identifier (32 bytes) || signing_share (32 bytes)
*/
export function teddsaKeyShareToBytes64(share: TeddsaKeyShare): Bytes64 {
const combined = new Uint8Array(64);
combined.set(share.identifier.toUint8Array(), 0);
combined.set(share.signing_share.toUint8Array(), 32);

const result = Bytes.fromUint8Array(combined, 64);
if (!result.success) {
throw new Error(`Failed to create Bytes64: ${result.err}`);
}
return result.data;
}

/**
* Deserialize Bytes64 to TeddsaKeyShare.
*/
export function bytes64ToTeddsaKeyShare(bytes: Bytes64): TeddsaKeyShare {
const arr = bytes.toUint8Array();

const identifierResult = Bytes.fromUint8Array(arr.slice(0, 32), 32);
if (!identifierResult.success) {
throw new Error(`Failed to extract identifier: ${identifierResult.err}`);
}

const signingResult = Bytes.fromUint8Array(arr.slice(32, 64), 32);
if (!signingResult.success) {
throw new Error(`Failed to extract signing_share: ${signingResult.err}`);
}

return {
identifier: identifierResult.data,
signing_share: signingResult.data,
};
}

/**
* Convert TeddsaKeyShare to 128-char hex string (for KS node API).
*/
export function teddsaKeyShareToHex(share: TeddsaKeyShare): string {
return teddsaKeyShareToBytes64(share).toHex();
}

/**
* Convert 128-char hex string to TeddsaKeyShare.
*/
export function hexToTeddsaKeyShare(hex: string): TeddsaKeyShare {
const bytesResult = Bytes.fromHexString(hex, 64);
if (!bytesResult.success) {
throw new Error(
`Invalid hex string for TeddsaKeyShare: ${bytesResult.err}`,
);
}
return bytes64ToTeddsaKeyShare(bytesResult.data);
}

/**
* Convert TeddsaKeyShare to Point256 (same structure, different semantics).
* Use when reusing existing Ed25519 functions.
*/
export function teddsaKeyShareToPoint256(share: TeddsaKeyShare): Point256 {
return {
x: share.identifier,
y: share.signing_share,
};
}

/**
* Convert Point256 to TeddsaKeyShare.
*/
export function point256ToTeddsaKeyShare(point: Point256): TeddsaKeyShare {
return {
identifier: point.x,
signing_share: point.y,
};
}
150 changes: 0 additions & 150 deletions crypto/teddsa/frost_ed25519_keplr/tests/integration_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -379,153 +379,3 @@ fn check_sign_with_incorrect_commitments() {
rng,
);
}

/// Test to verify the relationship between identifier and verifying_share.
///
/// In FROST Ed25519:
/// - identifier: SSS polynomial x-coordinate (scalar, 32 bytes)
/// - signing_share: f(identifier) where f is secret polynomial (scalar, 32 bytes)
/// - verifying_share: signing_share * G (EdwardsPoint, compressed 32 bytes)
///
/// The compressed EdwardsY format stores: y-coordinate (255 bits) + x sign bit (1 bit)
/// This test extracts the actual x,y coordinates from verifying_share and verifies
/// that identifier is NOT the x-coordinate of the point (it's the polynomial x-value).
#[test]
fn check_identifier_is_not_verifying_share_x_coordinate() {
use curve25519_dalek::edwards::CompressedEdwardsY;

let mut rng = rand::rngs::OsRng;

// Generate keys with dealer
let max_signers = 3;
let min_signers = 2;
let (shares, pubkeys) = keys::generate_with_dealer(
max_signers,
min_signers,
keys::IdentifierList::Default,
&mut rng,
)
.unwrap();

// For each participant, check the relationship
for (identifier, secret_share) in &shares {
// Get the key package
let key_package: keys::KeyPackage = secret_share.clone().try_into().unwrap();

// Get verifying_share bytes (compressed EdwardsY format)
let verifying_share_bytes = key_package.verifying_share().serialize().unwrap();
assert_eq!(
verifying_share_bytes.len(),
32,
"verifying_share should be 32 bytes"
);

// Decompress to get actual point coordinates
let compressed = CompressedEdwardsY::from_slice(&verifying_share_bytes).unwrap();
let point = compressed.decompress().expect("valid point");

// Get the actual x and y coordinates (as field elements, in bytes)
// EdwardsPoint internally stores (X, Y, Z, T) in extended coordinates
// To get affine x, y: x = X/Z, y = Y/Z
let point_bytes = point.compress().to_bytes();

// Get identifier bytes
let identifier_bytes = identifier.serialize();
assert_eq!(identifier_bytes.len(), 32, "identifier should be 32 bytes");

// The compressed format is y-coordinate with x's sign bit in the MSB
// So the first 255 bits are y, and bit 255 is x's sign
// identifier is a scalar (the x-value in SSS polynomial), NOT the point's x-coordinate

// Verify that identifier != compressed point bytes (they should be different)
assert_ne!(
identifier_bytes, verifying_share_bytes,
"identifier should NOT equal verifying_share compressed bytes"
);

// Also verify that signing_share * G = verifying_share
let signing_share_bytes = key_package.signing_share().serialize();
assert_eq!(
signing_share_bytes.len(),
32,
"signing_share should be 32 bytes"
);

// The verifying_share from pubkeys should match
let pubkey_verifying_share = pubkeys.verifying_shares().get(identifier).unwrap();
assert_eq!(
key_package.verifying_share().serialize().unwrap(),
pubkey_verifying_share.serialize().unwrap(),
"verifying_share should match in key_package and public_key_package"
);

println!("Participant {:?}:", identifier);
println!(
" identifier bytes: {}",
hex::encode(&identifier_bytes)
);
println!(
" signing_share bytes: {}",
hex::encode(&signing_share_bytes)
);
println!(
" verifying_share bytes: {}",
hex::encode(&verifying_share_bytes)
);
}
}

/// Test to extract x-coordinate from verifying_share (compressed EdwardsY point).
///
/// Ed25519 compressed format: y-coordinate (255 bits) + x sign bit (1 bit) = 32 bytes
/// To get x-coordinate, we need to decompress the point.
#[test]
fn check_extract_x_coordinate_from_verifying_share() {
use curve25519_dalek::edwards::CompressedEdwardsY;

let mut rng = rand::rngs::OsRng;

let max_signers = 3;
let min_signers = 2;
let (shares, _pubkeys) = keys::generate_with_dealer(
max_signers,
min_signers,
keys::IdentifierList::Default,
&mut rng,
)
.unwrap();

for (identifier, secret_share) in &shares {
let key_package: keys::KeyPackage = secret_share.clone().try_into().unwrap();

// Get verifying_share (compressed point)
let verifying_share_bytes = key_package.verifying_share().serialize().unwrap();

// Decompress
let compressed = CompressedEdwardsY::from_slice(&verifying_share_bytes).unwrap();
let point = compressed.decompress().expect("valid point");

// Extract y-coordinate from compressed bytes (first 255 bits)
let mut y_bytes = verifying_share_bytes.clone();
y_bytes[31] &= 0x7F; // Clear the sign bit to get pure y

// The x sign bit
let x_sign = (verifying_share_bytes[31] >> 7) & 1;

println!("Participant {:?}:", identifier);
println!(
" compressed bytes: {}",
hex::encode(&verifying_share_bytes)
);
println!(" y-coordinate: {}", hex::encode(&y_bytes));
println!(" x sign bit: {}", x_sign);

// Verify the point is valid by recompressing
let recompressed = point.compress();
assert_eq!(
recompressed.to_bytes(),
verifying_share_bytes.as_slice(),
"recompressed point should match original"
);
}
}
2 changes: 0 additions & 2 deletions crypto/teddsa/frost_ed25519_keplr_wasm/wasm/src/keys/mod.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
mod identifier;
mod key_package;
mod public_key_package;
mod scalar_mult;

pub use identifier::*;
pub use key_package::*;
pub use public_key_package::*;
pub use scalar_mult::*;

This file was deleted.

35 changes: 0 additions & 35 deletions embed/oko_attached/src/crypto/scalar.ts

This file was deleted.

Loading