From ec7643a3414ef97e7d9ac1608a282aa4de4d8b99 Mon Sep 17 00:00:00 2001 From: Dan Date: Tue, 13 Jan 2026 12:14:49 +0900 Subject: [PATCH 1/5] sdk_core: add embeddable "sign in" modal component (Preact) * oko_sdk_core: add login modal for OAuth provider selection * oko_sdk_core: add dark mode support to login modal * oko_sdk_core: apply review feebacks * oko_sdk_core: rename login to openConnectModal * refactor: simplify wallet connection API with openConnectModal * oko_sdk_core: rename login to openSignInModal * oko_sdk_core: add loading/failed progress views to login modal * oko_sdk_core: rename login_modal to signin_modal * oko_sdk_core: use HTML templates * oko_cosmos_kit: prevent double signin modal on cancel * oko_sdk_core: migrate signin_modal to Preact components * oko_sdk_core: extract container ID to constant --------- Co-authored-by: Elden Park --- .../v0/sdk-usage/cosmos-kit-integration.md | 46 +- .../sdk-usage/interchain-kit-integration.md | 48 +- examples/cosmoskit_nextjs/app/page.tsx | 6 +- .../components/ConnectWalletButton.tsx | 4 +- examples/interchainkit_nextjs/app/page.tsx | 10 +- sandbox/sandbox_cosmos_kit/app/page.tsx | 6 +- .../src/services/web3/wagmiConfig.tsx | 4 +- sandbox/sandbox_interchain_kit/app/page.tsx | 10 +- sandbox/sandbox_sol/src/hooks/use_oko_sol.ts | 4 +- sdk/oko_cosmos_kit/src/chain-wallet.ts | 1 + sdk/oko_cosmos_kit/src/client.ts | 22 +- sdk/oko_cosmos_kit/src/constant.ts | 22 - sdk/oko_cosmos_kit/src/index.ts | 33 +- sdk/oko_cosmos_kit/src/main-wallet.ts | 4 +- sdk/oko_cosmos_kit/src/types.ts | 14 +- sdk/oko_interchain_kit/src/constant.ts | 23 - sdk/oko_interchain_kit/src/index.ts | 33 +- sdk/oko_interchain_kit/src/oko-wallet.ts | 11 +- sdk/oko_interchain_kit/src/types.ts | 16 - sdk/oko_sdk_core/package.json | 3 +- .../src/methods/open_sign_in_modal.ts | 27 + sdk/oko_sdk_core/src/oko.ts | 2 + sdk/oko_sdk_core/src/types/oko_wallet.ts | 1 + .../signin_modal/components/default_view.tsx | 88 ++++ .../src/ui/signin_modal/components/icons.tsx | 207 ++++++++ .../signin_modal/components/progress_view.tsx | 58 +++ .../components/provider_button.tsx | 30 ++ .../signin_modal/components/socials_view.tsx | 47 ++ .../src/ui/signin_modal/hooks/use_theme.ts | 74 +++ sdk/oko_sdk_core/src/ui/signin_modal/icons.ts | 12 + sdk/oko_sdk_core/src/ui/signin_modal/index.ts | 2 + .../src/ui/signin_modal/render.tsx | 54 ++ .../src/ui/signin_modal/signin_modal.tsx | 106 ++++ .../src/ui/signin_modal/styles.ts | 463 ++++++++++++++++++ sdk/oko_sdk_core/src/ui/signin_modal/types.ts | 15 + sdk/oko_sdk_core/tsconfig.json | 2 + sdk/oko_sdk_sol/src/wallet-standard/wallet.ts | 2 +- yarn.lock | 8 + 38 files changed, 1265 insertions(+), 253 deletions(-) create mode 100644 sdk/oko_sdk_core/src/methods/open_sign_in_modal.ts create mode 100644 sdk/oko_sdk_core/src/ui/signin_modal/components/default_view.tsx create mode 100644 sdk/oko_sdk_core/src/ui/signin_modal/components/icons.tsx create mode 100644 sdk/oko_sdk_core/src/ui/signin_modal/components/progress_view.tsx create mode 100644 sdk/oko_sdk_core/src/ui/signin_modal/components/provider_button.tsx create mode 100644 sdk/oko_sdk_core/src/ui/signin_modal/components/socials_view.tsx create mode 100644 sdk/oko_sdk_core/src/ui/signin_modal/hooks/use_theme.ts create mode 100644 sdk/oko_sdk_core/src/ui/signin_modal/icons.ts create mode 100644 sdk/oko_sdk_core/src/ui/signin_modal/index.ts create mode 100644 sdk/oko_sdk_core/src/ui/signin_modal/render.tsx create mode 100644 sdk/oko_sdk_core/src/ui/signin_modal/signin_modal.tsx create mode 100644 sdk/oko_sdk_core/src/ui/signin_modal/styles.ts create mode 100644 sdk/oko_sdk_core/src/ui/signin_modal/types.ts diff --git a/apps/docs_web/docs/v0/sdk-usage/cosmos-kit-integration.md b/apps/docs_web/docs/v0/sdk-usage/cosmos-kit-integration.md index 226ac76e7..35bd1b0c7 100644 --- a/apps/docs_web/docs/v0/sdk-usage/cosmos-kit-integration.md +++ b/apps/docs_web/docs/v0/sdk-usage/cosmos-kit-integration.md @@ -36,21 +36,16 @@ npm install @cosmjs/amino @cosmjs/proto-signing ## Basic Setup -### 1. Create Oko Wallets +### 1. Create Oko Wallet -Use `makeOkoWallets` to generate wallet instances for your desired login -providers: +Use `makeOkoWallet` to create a wallet instance: ```typescript -import { makeOkoWallets } from "@oko-wallet/oko-cosmos-kit"; +import { makeOkoWallet } from "@oko-wallet/oko-cosmos-kit"; -const okoWallets = makeOkoWallets({ +const okoWallet = makeOkoWallet({ apiKey: "your-oko-api-key", sdkEndpoint: "https://your-custom-oko-sdk.example.com", // optional, Only specify if you have your own SDK endpoint - loginMethods: [ - { provider: "google" }, - // optional, Specify which login providers to enable. If not specified, all available providers will be included - ], }); ``` @@ -61,10 +56,10 @@ wallets: ```typescript import { ChainProvider } from "@cosmos-kit/react"; -import { makeOkoWallets } from "@oko-wallet/oko-cosmos-kit"; +import { makeOkoWallet } from "@oko-wallet/oko-cosmos-kit"; import { chains, assets } from "chain-registry"; -const okoWallets = makeOkoWallets({ +const okoWallet = makeOkoWallet({ apiKey: "your-oko-api-key", }); @@ -73,7 +68,7 @@ export default function App({ Component, pageProps }) { @@ -116,7 +111,7 @@ function WalletConnect() { ### OkoWalletOptions -The `makeOkoWallets` function accepts the following options: +The `makeOkoWallet` function accepts the following options: ```typescript interface OkoWalletOptions { @@ -126,31 +121,18 @@ interface OkoWalletOptions { // Custom SDK endpoint (optional) // Defaults to Oko's production endpoint sdkEndpoint?: string; - - // Login methods to enable (optional) - // If not specified, all available providers will be enabled - loginMethods?: OkoLoginMethod[]; -} - -interface OkoLoginMethod { - provider: SignInType; } - -type SignInType = "google" | "email" | "x" | "telegram" | "discord"; ``` ### Login Providers -Each login provider creates a separate wallet entry in Cosmos Kit's wallet list: - -- `oko_wallet_google` - Google OAuth login -- `oko_wallet_email` - Email/passwordless login -- `oko_wallet_x` - X (Twitter) OAuth login -- `oko_wallet_telegram` - Telegram login -- `oko_wallet_discord` - Discord OAuth login +When connecting, users can select their preferred login provider from a modal: -When `loginMethods` is not specified, all available providers are automatically -included. +- Google OAuth +- Email/passwordless +- X (Twitter) OAuth +- Telegram OAuth +- Discord OAuth ## Next Steps diff --git a/apps/docs_web/docs/v0/sdk-usage/interchain-kit-integration.md b/apps/docs_web/docs/v0/sdk-usage/interchain-kit-integration.md index 69ffcdfab..7ced93fd7 100644 --- a/apps/docs_web/docs/v0/sdk-usage/interchain-kit-integration.md +++ b/apps/docs_web/docs/v0/sdk-usage/interchain-kit-integration.md @@ -33,22 +33,16 @@ npm install @oko-wallet/oko-interchain-kit @interchain-kit/react @interchain-kit ## Basic Setup -### 1. Create Oko Wallets +### 1. Create Oko Wallet -Use `makeOkoWallets` to generate wallet instances for your desired login -providers: +Use `makeOkoWallet` to create a wallet instance: ```typescript -import { makeOkoWallets } from "@oko-wallet/oko-interchain-kit"; +import { makeOkoWallet } from "@oko-wallet/oko-interchain-kit"; -const okoWallets = makeOkoWallets({ +const okoWallet = makeOkoWallet({ apiKey: "your-oko-api-key", sdkEndpoint: "https://your-custom-oko-sdk.example.com", // optional, Only specify if you have your own SDK endpoint - loginMethods: [ - { provider: "google" }, - { provider: "email" }, - // optional, Specify which login providers to enable. If not specified, all available providers will be included - ], }); ``` @@ -59,10 +53,10 @@ wallets: ```typescript import { ChainProvider } from "@interchain-kit/react"; -import { makeOkoWallets } from "@oko-wallet/oko-interchain-kit"; +import { makeOkoWallet } from "@oko-wallet/oko-interchain-kit"; import { chains, assetLists } from "@chain-registry/v2"; -const okoWallets = makeOkoWallets({ +const okoWallet = makeOkoWallet({ apiKey: "your-oko-api-key", }); @@ -71,7 +65,7 @@ export default function App({ Component, pageProps }) { @@ -109,7 +103,7 @@ function WalletConnect() { ### OkoWalletOptions -The `makeOkoWallets` function accepts the following options: +The `makeOkoWallet` function accepts the following options: ```typescript interface OkoWalletOptions { @@ -119,32 +113,18 @@ interface OkoWalletOptions { // Custom SDK endpoint (optional) // Defaults to Oko's production endpoint sdkEndpoint?: string; - - // Login methods to enable (optional) - // If not specified, all available providers will be enabled - loginMethods?: OkoLoginMethod[]; -} - -interface OkoLoginMethod { - provider: SignInType; } - -type SignInType = "google" | "email" | "x" | "telegram" | "discord"; ``` ### Login Providers -Each login provider creates a separate wallet entry in Interchain Kit's wallet -list: - -- `oko-wallet_google` - Google OAuth login -- `oko-wallet_email` - Email/passwordless login -- `oko-wallet_x` - X (Twitter) OAuth login -- `oko-wallet_telegram` - Telegram login -- `oko-wallet_discord` - Discord OAuth login +When connecting, users can select their preferred login provider from a modal: -When `loginMethods` is not specified, all available providers are automatically -included. +- Google OAuth +- Email/passwordless +- X (Twitter) OAuth +- Telegram OAuth +- Discord OAuth ## Signing Transactions diff --git a/examples/cosmoskit_nextjs/app/page.tsx b/examples/cosmoskit_nextjs/app/page.tsx index 789a79b51..e2d5bca69 100644 --- a/examples/cosmoskit_nextjs/app/page.tsx +++ b/examples/cosmoskit_nextjs/app/page.tsx @@ -2,7 +2,7 @@ import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; import { ChainProvider } from "@cosmos-kit/react"; -import { makeOkoWallets } from "@oko-wallet/oko-cosmos-kit"; +import { makeOkoWallet } from "@oko-wallet/oko-cosmos-kit"; import { chains, assets } from "chain-registry"; import App from "@/components/App"; import "@interchain-ui/react/styles"; @@ -10,7 +10,7 @@ import "@interchain-ui/react/styles"; const queryClient = new QueryClient(); export default function Home() { - const okoWallets = makeOkoWallets({ + const okoWallet = makeOkoWallet({ apiKey: process.env.NEXT_PUBLIC_OKO_API_KEY!, }); return ( @@ -18,7 +18,7 @@ export default function Home() { diff --git a/examples/evm_wagmi_nextjs/components/ConnectWalletButton.tsx b/examples/evm_wagmi_nextjs/components/ConnectWalletButton.tsx index b03b2f975..6db7f14de 100644 --- a/examples/evm_wagmi_nextjs/components/ConnectWalletButton.tsx +++ b/examples/evm_wagmi_nextjs/components/ConnectWalletButton.tsx @@ -12,7 +12,7 @@ export default function ConnectWalletButton() { chain, openAccountModal, openChainModal, - openConnectModal, + openSignInModal, authenticationStatus, mounted, }) => { @@ -33,7 +33,7 @@ export default function ConnectWalletButton() { {(() => { if (!connected) { return ( - ); diff --git a/examples/interchainkit_nextjs/app/page.tsx b/examples/interchainkit_nextjs/app/page.tsx index f9fcfebba..e036250c6 100644 --- a/examples/interchainkit_nextjs/app/page.tsx +++ b/examples/interchainkit_nextjs/app/page.tsx @@ -4,7 +4,7 @@ import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; import { ChainProvider, InterchainWalletModal } from "@interchain-kit/react"; import { chains, assetLists } from "@chain-registry/v2"; import App from "@/components/App"; -import { makeOkoWallets } from "@oko-wallet/oko-interchain-kit"; +import { makeOkoWallet } from "@oko-wallet/oko-interchain-kit"; import "@interchain-kit/react/styles.css"; const queryClient = new QueryClient(); @@ -18,20 +18,20 @@ const filteredAssetLists = assetLists.filter( ); export default function Home() { - const okoWallets = + const okoWallet = typeof window !== "undefined" - ? makeOkoWallets({ + ? makeOkoWallet({ apiKey: process.env.NEXT_PUBLIC_OKO_API_KEY!, sdkEndpoint: process.env.NEXT_PUBLIC_OKO_SDK_ENDPOINT, }) - : []; + : null; return ( } > diff --git a/sandbox/sandbox_cosmos_kit/app/page.tsx b/sandbox/sandbox_cosmos_kit/app/page.tsx index 789a79b51..e2d5bca69 100644 --- a/sandbox/sandbox_cosmos_kit/app/page.tsx +++ b/sandbox/sandbox_cosmos_kit/app/page.tsx @@ -2,7 +2,7 @@ import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; import { ChainProvider } from "@cosmos-kit/react"; -import { makeOkoWallets } from "@oko-wallet/oko-cosmos-kit"; +import { makeOkoWallet } from "@oko-wallet/oko-cosmos-kit"; import { chains, assets } from "chain-registry"; import App from "@/components/App"; import "@interchain-ui/react/styles"; @@ -10,7 +10,7 @@ import "@interchain-ui/react/styles"; const queryClient = new QueryClient(); export default function Home() { - const okoWallets = makeOkoWallets({ + const okoWallet = makeOkoWallet({ apiKey: process.env.NEXT_PUBLIC_OKO_API_KEY!, }); return ( @@ -18,7 +18,7 @@ export default function Home() { diff --git a/sandbox/sandbox_evm/src/services/web3/wagmiConfig.tsx b/sandbox/sandbox_evm/src/services/web3/wagmiConfig.tsx index 9f1d9f363..7150c95d7 100644 --- a/sandbox/sandbox_evm/src/services/web3/wagmiConfig.tsx +++ b/sandbox/sandbox_evm/src/services/web3/wagmiConfig.tsx @@ -130,9 +130,9 @@ function okoConnector( // popup on safari works fine here as we use cached states console.log( - "[sandbox-evm] no authenticated account, sign in with google", + "[sandbox-evm] no authenticated account, opening connect modal", ); - await okoEthWallet.okoWallet.signIn("google"); + await okoEthWallet.okoWallet.openSignInModal(); } const chainId = await wallet.getChainId(); diff --git a/sandbox/sandbox_interchain_kit/app/page.tsx b/sandbox/sandbox_interchain_kit/app/page.tsx index 802d7e5f5..8cc60e2ee 100644 --- a/sandbox/sandbox_interchain_kit/app/page.tsx +++ b/sandbox/sandbox_interchain_kit/app/page.tsx @@ -4,7 +4,7 @@ import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; import { ChainProvider, InterchainWalletModal } from "@interchain-kit/react"; import { chains, assetLists } from "@chain-registry/v2"; import App from "@/components/App"; -import { makeOkoWallets } from "@oko-wallet/oko-interchain-kit"; +import { makeOkoWallet } from "@oko-wallet/oko-interchain-kit"; import "@interchain-kit/react/styles.css"; const queryClient = new QueryClient(); @@ -16,20 +16,20 @@ const filteredAssetLists = assetLists.filter( ); export default function Home() { - const okoWallets = + const okoWallet = typeof window !== "undefined" - ? makeOkoWallets({ + ? makeOkoWallet({ apiKey: process.env.NEXT_PUBLIC_OKO_API_KEY!, sdkEndpoint: process.env.NEXT_PUBLIC_OKO_SDK_ENDPOINT, }) - : []; + : null; return ( } > diff --git a/sandbox/sandbox_sol/src/hooks/use_oko_sol.ts b/sandbox/sandbox_sol/src/hooks/use_oko_sol.ts index 291fca00d..40a3ed835 100644 --- a/sandbox/sandbox_sol/src/hooks/use_oko_sol.ts +++ b/sandbox/sandbox_sol/src/hooks/use_oko_sol.ts @@ -98,8 +98,8 @@ export function useOkoSol() { // Check if user is signed in const existingPubkey = await okoSolWallet.okoWallet.getPublicKey(); if (!existingPubkey) { - // Not signed in - trigger OAuth sign in - await okoSolWallet.okoWallet.signIn("google"); + // Not signed in - open provider select modal + await okoSolWallet.okoWallet.openSignInModal(); } // connect() internally handles Ed25519 key creation if needed diff --git a/sdk/oko_cosmos_kit/src/chain-wallet.ts b/sdk/oko_cosmos_kit/src/chain-wallet.ts index f8ab63821..995456ca9 100644 --- a/sdk/oko_cosmos_kit/src/chain-wallet.ts +++ b/sdk/oko_cosmos_kit/src/chain-wallet.ts @@ -25,4 +25,5 @@ export class OkoChainWallet extends ChainWalletBase { await super.update(); } + } diff --git a/sdk/oko_cosmos_kit/src/client.ts b/sdk/oko_cosmos_kit/src/client.ts index cca3b1675..d753e3158 100644 --- a/sdk/oko_cosmos_kit/src/client.ts +++ b/sdk/oko_cosmos_kit/src/client.ts @@ -19,12 +19,10 @@ import type { WalletClient, } from "@cosmos-kit/core"; import { BroadcastMode } from "@keplr-wallet/types"; -import type { SignInType } from "@oko-wallet/oko-sdk-core"; import type { OkoCosmosWalletInterface } from "@oko-wallet/oko-sdk-cosmos"; export class OkoWalletClient implements WalletClient { readonly client: OkoCosmosWalletInterface; - readonly loginProvider: SignInType; private _defaultSignOptions: SignOptions = { preferNoSetFee: false, preferNoSetMemo: false, @@ -39,25 +37,10 @@ export class OkoWalletClient implements WalletClient { this._defaultSignOptions = options; } - constructor(client: OkoCosmosWalletInterface, loginProvider: SignInType) { + constructor(client: OkoCosmosWalletInterface) { this.client = client; - this.loginProvider = loginProvider; } - // async startEmailSignIn(email: string) { - // if (this.loginProvider !== 'email') { - // throw new Error('Email login is not enabled for this wallet instance'); - // } - // return await this.client.okoWallet.startEmailSignIn(email); - // } - - // async completeEmailSignIn(email: string, code: string) { - // if (this.loginProvider !== 'email') { - // throw new Error('Email login is not enabled for this wallet instance'); - // } - // return await this.client.okoWallet.completeEmailSignIn(email, code); - // } - async enable(_chainIds: string | string[]) {} async suggestToken(_suggestToken: SuggestToken) {} @@ -77,9 +60,8 @@ export class OkoWalletClient implements WalletClient { if (!publicKey) { try { - await this.client.okoWallet.signIn(this.loginProvider); + await this.client.okoWallet.openSignInModal(); } catch { - // Must match rejectMessage.source in registry.ts for cosmos-kit to recognize rejection throw new Error("Request rejected"); } } diff --git a/sdk/oko_cosmos_kit/src/constant.ts b/sdk/oko_cosmos_kit/src/constant.ts index 57e62b385..0dc663532 100644 --- a/sdk/oko_cosmos_kit/src/constant.ts +++ b/sdk/oko_cosmos_kit/src/constant.ts @@ -4,25 +4,3 @@ export const OKO_ICON = export const GOOGLE_LOGO = "data:image/png;base64,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"; -export const PROVIDER_CONFIG: Record = { - google: { - logo: GOOGLE_LOGO, - name: "Oko Wallet (Google)", - }, - email: { - logo: OKO_ICON, - name: "Oko Wallet (Email)", - }, - x: { - logo: OKO_ICON, - name: "Oko Wallet (X)", - }, - telegram: { - logo: OKO_ICON, - name: "Oko Wallet (Telegram)", - }, - discord: { - logo: OKO_ICON, - name: "Oko Wallet (Discord)", - }, -}; diff --git a/sdk/oko_cosmos_kit/src/index.ts b/sdk/oko_cosmos_kit/src/index.ts index 2dd33efb8..cc6c1653f 100644 --- a/sdk/oko_cosmos_kit/src/index.ts +++ b/sdk/oko_cosmos_kit/src/index.ts @@ -1,34 +1,11 @@ -import type { SignInType } from "@oko-wallet/oko-sdk-core"; - -import { PROVIDER_CONFIG } from "./constant"; import { OkoMainWallet } from "./main-wallet"; import { okoWalletInfo } from "./registry"; import type { OkoWalletOptions } from "./types"; -export const makeOkoWallets = (options: OkoWalletOptions): OkoMainWallet[] => { - // If no loginMethods specified, use all available providers - const providers = - options.loginMethods?.map((m) => m.provider) ?? - (Object.keys(PROVIDER_CONFIG) as SignInType[]); - - return providers.map((provider) => { - const providerConfig = PROVIDER_CONFIG[provider]; - - const { loginMethods, ...baseOptions } = options; - const internalOptions = { - ...baseOptions, - loginProvider: provider, - }; - - return new OkoMainWallet({ - ...okoWalletInfo, - name: okoWalletInfo.name + "_" + provider, - prettyName: providerConfig?.name || okoWalletInfo.prettyName, - logo: providerConfig?.logo - ? { major: okoWalletInfo.logo as string, minor: providerConfig.logo } - : okoWalletInfo.logo, - options: internalOptions, - }); +export const makeOkoWallet = (options: OkoWalletOptions): OkoMainWallet => { + return new OkoMainWallet({ + ...okoWalletInfo, + options, }); }; @@ -36,4 +13,4 @@ export { OkoChainWallet } from "./chain-wallet"; export { OkoWalletClient } from "./client"; export { OkoMainWallet } from "./main-wallet"; export { okoWalletInfo } from "./registry"; -export type { OkoLoginMethod, OkoWalletOptions } from "./types"; +export type { OkoWalletOptions } from "./types"; diff --git a/sdk/oko_cosmos_kit/src/main-wallet.ts b/sdk/oko_cosmos_kit/src/main-wallet.ts index 13b4153c0..8f5c95dad 100644 --- a/sdk/oko_cosmos_kit/src/main-wallet.ts +++ b/sdk/oko_cosmos_kit/src/main-wallet.ts @@ -46,9 +46,7 @@ export class OkoMainWallet extends MainWalletBase { throw new Error("Failed to initialize OkoCosmosWallet"); } - this.initClientDone( - new OkoWalletClient(cosmosWallet.data, options.loginProvider), - ); + this.initClientDone(new OkoWalletClient(cosmosWallet.data)); } catch (error) { this.initClientError(error as Error); } diff --git a/sdk/oko_cosmos_kit/src/types.ts b/sdk/oko_cosmos_kit/src/types.ts index 33438f9c4..ea84895d1 100644 --- a/sdk/oko_cosmos_kit/src/types.ts +++ b/sdk/oko_cosmos_kit/src/types.ts @@ -1,20 +1,8 @@ import type { Wallet } from "@cosmos-kit/core"; -import type { SignInType } from "@oko-wallet/oko-sdk-core"; - -export interface OkoLoginMethod { - provider: SignInType; -} export interface OkoWalletOptions { apiKey: string; sdkEndpoint?: string; - loginMethods?: OkoLoginMethod[]; -} - -export interface OkoWalletInternalOptions { - apiKey: string; - sdkEndpoint?: string; - loginProvider: SignInType; } -export type OkoWalletInfo = Wallet & { options: OkoWalletInternalOptions }; +export type OkoWalletInfo = Wallet & { options: OkoWalletOptions }; diff --git a/sdk/oko_interchain_kit/src/constant.ts b/sdk/oko_interchain_kit/src/constant.ts index 147d84f42..d13b4b01b 100644 --- a/sdk/oko_interchain_kit/src/constant.ts +++ b/sdk/oko_interchain_kit/src/constant.ts @@ -1,25 +1,2 @@ export const OKO_ICON = "data:image/png;base64,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"; - -export const PROVIDER_CONFIG: Record = { - google: { - logo: OKO_ICON, - name: "Oko Wallet (Google)", - }, - email: { - logo: OKO_ICON, - name: "Oko Wallet (Email)", - }, - x: { - logo: OKO_ICON, - name: "Oko Wallet (X)", - }, - telegram: { - logo: OKO_ICON, - name: "Oko Wallet (Telegram)", - }, - discord: { - logo: OKO_ICON, - name: "Oko Wallet (Discord)", - }, -}; diff --git a/sdk/oko_interchain_kit/src/index.ts b/sdk/oko_interchain_kit/src/index.ts index 54c93b1e3..bd8469d44 100644 --- a/sdk/oko_interchain_kit/src/index.ts +++ b/sdk/oko_interchain_kit/src/index.ts @@ -1,43 +1,18 @@ -import type { SignInType } from "@oko-wallet/oko-sdk-core"; - import { OkoWallet } from "./oko-wallet"; import { okoWalletInfo } from "./registry"; import type { OkoWalletOptions } from "./types"; import { initializeOkoCosmosWallet } from "./init"; -import { PROVIDER_CONFIG } from "./constant"; -export const makeOkoWallets = (options: OkoWalletOptions): OkoWallet[] => { +export const makeOkoWallet = (options: OkoWalletOptions): OkoWallet => { if (typeof window === "undefined") { throw new Error( "Oko Wallet can only be initialized in browser environment", ); } - // If no loginMethods specified, use all available providers - const providers = - options.loginMethods?.map((m) => m.provider) ?? - (Object.keys(PROVIDER_CONFIG) as SignInType[]); - - return providers.map((provider) => { - const providerConfig = PROVIDER_CONFIG[provider]; - - const internalOptions = { - ...options, - loginProvider: provider, - }; - - const okoClient = initializeOkoCosmosWallet(internalOptions); - - const walletInfo = { - ...okoWalletInfo, - name: okoWalletInfo.name + "_" + provider, - prettyName: providerConfig?.name || okoWalletInfo.prettyName, - logo: okoWalletInfo.logo, - }; - - return new OkoWallet(walletInfo, okoClient, provider); - }); + const okoClient = initializeOkoCosmosWallet(options); + return new OkoWallet(okoWalletInfo, okoClient); }; export { okoWalletInfo } from "./registry"; -export type { OkoLoginMethod, OkoWalletOptions } from "./types"; +export type { OkoWalletOptions } from "./types"; diff --git a/sdk/oko_interchain_kit/src/oko-wallet.ts b/sdk/oko_interchain_kit/src/oko-wallet.ts index 5271c24d5..7ec311ca1 100644 --- a/sdk/oko_interchain_kit/src/oko-wallet.ts +++ b/sdk/oko_interchain_kit/src/oko-wallet.ts @@ -1,5 +1,4 @@ import { CosmosWallet } from "@interchain-kit/core"; -import type { SignInType } from "@oko-wallet/oko-sdk-core"; import type { BroadcastMode, SignOptions, @@ -14,7 +13,6 @@ import type { OkoCosmosWalletInterface } from "@oko-wallet/oko-sdk-cosmos"; */ export class OkoWallet extends CosmosWallet { private okoClient: OkoCosmosWalletInterface; - private loginProvider: SignInType; defaultSignOptions: { preferNoSetFee: boolean; preferNoSetMemo: boolean; @@ -25,14 +23,9 @@ export class OkoWallet extends CosmosWallet { disableBalanceCheck: false, }; - constructor( - walletInfo: Wallet, - okoClient: OkoCosmosWalletInterface, - loginProvider: SignInType, - ) { + constructor(walletInfo: Wallet, okoClient: OkoCosmosWalletInterface) { super(walletInfo); this.okoClient = okoClient; - this.loginProvider = loginProvider; // Expose client for interchain-kit (this as any).client = okoClient; @@ -61,7 +54,7 @@ export class OkoWallet extends CosmosWallet { // If not signed in, trigger the sign-in flow if (!publicKey) { - await this.okoClient.okoWallet.signIn(this.loginProvider); + await this.okoClient.okoWallet.openSignInModal(); } const key = await this.okoClient.getKey(chainId); diff --git a/sdk/oko_interchain_kit/src/types.ts b/sdk/oko_interchain_kit/src/types.ts index 917a6960c..9e58c3753 100644 --- a/sdk/oko_interchain_kit/src/types.ts +++ b/sdk/oko_interchain_kit/src/types.ts @@ -1,20 +1,4 @@ -import type { Wallet } from "@interchain-kit/core"; -import type { SignInType } from "@oko-wallet/oko-sdk-core"; - -export interface OkoLoginMethod { - provider: SignInType; -} - export interface OkoWalletOptions { apiKey: string; sdkEndpoint?: string; - loginMethods?: OkoLoginMethod[]; -} - -export interface OkoWalletInternalOptions { - apiKey: string; - sdkEndpoint?: string; - loginProvider: SignInType; } - -export type OkoWalletInfo = Wallet & { options: OkoWalletInternalOptions }; diff --git a/sdk/oko_sdk_core/package.json b/sdk/oko_sdk_core/package.json index 4780595f6..1dbeb739d 100644 --- a/sdk/oko_sdk_core/package.json +++ b/sdk/oko_sdk_core/package.json @@ -34,7 +34,8 @@ "@keplr-wallet/types": "0.12.297", "@oko-wallet/bytes": "^0.0.3-alpha.65", "@oko-wallet/oko-types": "^0.0.1-alpha.5", - "@oko-wallet/stdlib-js": "^0.0.2-rc.45" + "@oko-wallet/stdlib-js": "^0.0.2-rc.45", + "preact": "^10.25.4" }, "devDependencies": { "@rollup/plugin-commonjs": "^25.0.0", diff --git a/sdk/oko_sdk_core/src/methods/open_sign_in_modal.ts b/sdk/oko_sdk_core/src/methods/open_sign_in_modal.ts new file mode 100644 index 000000000..5245dc811 --- /dev/null +++ b/sdk/oko_sdk_core/src/methods/open_sign_in_modal.ts @@ -0,0 +1,27 @@ +import type { OkoWalletInterface } from "@oko-wallet-sdk-core/types"; +import { renderSignInModal } from "@oko-wallet-sdk-core/ui/signin_modal"; + +const state = { isModalOpen: false }; + +export async function openSignInModal(this: OkoWalletInterface): Promise { + await this.waitUntilInitialized; + + if (state.isModalOpen) { + return; + } + state.isModalOpen = true; + + return new Promise((resolve, reject) => { + renderSignInModal({ + onSelect: async (provider) => { + await this.signIn(provider); + state.isModalOpen = false; + resolve(); + }, + onClose: () => { + state.isModalOpen = false; + reject(new Error("Sign in cancelled")); + }, + }); + }); +} diff --git a/sdk/oko_sdk_core/src/oko.ts b/sdk/oko_sdk_core/src/oko.ts index 72ae547e9..93acd44a2 100644 --- a/sdk/oko_sdk_core/src/oko.ts +++ b/sdk/oko_sdk_core/src/oko.ts @@ -1,6 +1,7 @@ import pJson from "../package.json"; import { sendMsgToIframe } from "./methods/send_msg_to_iframe"; import { openModal } from "./methods/open_modal"; +import { openSignInModal } from "./methods/open_sign_in_modal"; import { signIn } from "./methods/sign_in"; import { signOut } from "./methods/sign_out"; import { getPublicKey } from "./methods/get_public_key"; @@ -21,6 +22,7 @@ OkoWallet.version = pJson.version; const ptype: OkoWalletInterface = OkoWallet.prototype; ptype.openModal = openModal; +ptype.openSignInModal = openSignInModal; ptype.closeModal = closeModal; ptype.sendMsgToIframe = sendMsgToIframe; ptype.signIn = signIn; diff --git a/sdk/oko_sdk_core/src/types/oko_wallet.ts b/sdk/oko_sdk_core/src/types/oko_wallet.ts index d8a0c7767..04a3e2f1b 100644 --- a/sdk/oko_sdk_core/src/types/oko_wallet.ts +++ b/sdk/oko_sdk_core/src/types/oko_wallet.ts @@ -35,6 +35,7 @@ export interface OkoWalletInterface { openModal: ( msg: OkoWalletMsgOpenModal, ) => Promise>; + openSignInModal: () => Promise; closeModal: () => void; sendMsgToIframe: (msg: OkoWalletMsg) => Promise; signIn: (type: SignInType) => Promise; diff --git a/sdk/oko_sdk_core/src/ui/signin_modal/components/default_view.tsx b/sdk/oko_sdk_core/src/ui/signin_modal/components/default_view.tsx new file mode 100644 index 000000000..5b5052f4c --- /dev/null +++ b/sdk/oko_sdk_core/src/ui/signin_modal/components/default_view.tsx @@ -0,0 +1,88 @@ +import { type FunctionComponent as FC } from "preact"; + +import type { SignInType } from "@oko-wallet-sdk-core/types/oauth"; +import type { ResolvedTheme } from "../types"; +import { S3_LOGO_URL, S3_LOGO_WITH_NAME_URL } from "../icons"; +import { ProviderButton } from "./provider_button"; +import { + EmailIcon, + GoogleIcon, + XSmallIcon, + TelegramSmallIcon, + AppleSmallIcon, + ChevronRightIcon, + ExternalLinkIcon, +} from "./icons"; + +export interface DefaultViewProps { + theme: ResolvedTheme; + onSelect: (provider: SignInType) => void; + onShowSocials: () => void; +} + +export const DefaultView: FC = ({ + theme, + onSelect, + onShowSocials, +}) => { + return ( +
+
+ Oko +
+
+ } + label="Email" + onClick={() => onSelect("email")} + /> + } + label="Google" + onClick={() => onSelect("google")} + /> + +
+ +
+ ); +}; diff --git a/sdk/oko_sdk_core/src/ui/signin_modal/components/icons.tsx b/sdk/oko_sdk_core/src/ui/signin_modal/components/icons.tsx new file mode 100644 index 000000000..dd1f36eab --- /dev/null +++ b/sdk/oko_sdk_core/src/ui/signin_modal/components/icons.tsx @@ -0,0 +1,207 @@ +import { type FunctionComponent as FC } from "preact"; + +export const GoogleIcon: FC = () => ( + + + + + + +); + +export const EmailIcon: FC = () => ( + + + + +); + +export const XIcon: FC = () => ( + + + +); + +export const XSmallIcon: FC = () => ( + + + +); + +export const TelegramIcon: FC = () => ( + + + + + + + + + + +); + +export const TelegramSmallIcon: FC = () => ( + + + + + + + + + + +); + +export const DiscordIcon: FC = () => ( + + + +); + +export const AppleIcon: FC = () => ( + + + +); + +export const AppleSmallIcon: FC = () => ( + + + +); + +export const CloseIcon: FC = () => ( + + + +); + +export const ChevronLeftIcon: FC = () => ( + + + +); + +export const ChevronRightIcon: FC = () => ( + + + +); + +export const ExternalLinkIcon: FC = () => ( + + + +); + +export const SpinnerLoadingIcon: FC = () => ( + + + +); + +export const SpinnerFailedIcon: FC = () => ( + + + +); diff --git a/sdk/oko_sdk_core/src/ui/signin_modal/components/progress_view.tsx b/sdk/oko_sdk_core/src/ui/signin_modal/components/progress_view.tsx new file mode 100644 index 000000000..6bd0e7ca4 --- /dev/null +++ b/sdk/oko_sdk_core/src/ui/signin_modal/components/progress_view.tsx @@ -0,0 +1,58 @@ +import { type FunctionComponent as FC } from "preact"; + +import type { SignInType } from "@oko-wallet-sdk-core/types/oauth"; +import { + GoogleIcon, + EmailIcon, + XIcon, + TelegramIcon, + DiscordIcon, + SpinnerLoadingIcon, + SpinnerFailedIcon, +} from "./icons"; + +export interface ProgressViewProps { + status: "loading" | "failed"; + provider: SignInType; + onRetry: () => void; +} + +const PROVIDER_ICONS: Record = { + email: EmailIcon, + google: GoogleIcon, + x: XIcon, + telegram: TelegramIcon, + discord: DiscordIcon, +}; + +export const ProgressView: FC = ({ + status, + provider, + onRetry, +}) => { + const isLoading = status === "loading"; + const ProviderIcon = PROVIDER_ICONS[provider]; + + return ( +
+
+ + + + + {isLoading ? : } + +
+
+ {isLoading ? "Signing in" : "Login failed"} +
+ {status === "failed" && ( + + )} +
+ ); +}; diff --git a/sdk/oko_sdk_core/src/ui/signin_modal/components/provider_button.tsx b/sdk/oko_sdk_core/src/ui/signin_modal/components/provider_button.tsx new file mode 100644 index 000000000..980a4528e --- /dev/null +++ b/sdk/oko_sdk_core/src/ui/signin_modal/components/provider_button.tsx @@ -0,0 +1,30 @@ +import { type FunctionComponent, type ComponentChildren } from "preact"; + +export interface ProviderButtonProps { + icon: ComponentChildren; + label: string; + onClick?: () => void; + disabled?: boolean; + chevron?: ComponentChildren; +} + +export const ProviderButton: FunctionComponent = ({ + icon, + label, + onClick, + disabled = false, + chevron, +}) => { + return ( + + ); +}; diff --git a/sdk/oko_sdk_core/src/ui/signin_modal/components/socials_view.tsx b/sdk/oko_sdk_core/src/ui/signin_modal/components/socials_view.tsx new file mode 100644 index 000000000..c0864c0cf --- /dev/null +++ b/sdk/oko_sdk_core/src/ui/signin_modal/components/socials_view.tsx @@ -0,0 +1,47 @@ +import { type FunctionComponent as FC } from "preact"; + +import type { SignInType } from "@oko-wallet-sdk-core/types/oauth"; +import { ProviderButton } from "./provider_button"; +import { + XIcon, + TelegramIcon, + DiscordIcon, + AppleIcon, + ChevronLeftIcon, +} from "./icons"; + +export interface SocialsViewProps { + onSelect: (provider: SignInType) => void; + onBack: () => void; +} + +export const SocialsView: FC = ({ onSelect, onBack }) => { + return ( +
+
+ + Login or sign up +
+
+ } + label="X" + onClick={() => onSelect("x")} + /> + } + label="Telegram" + onClick={() => onSelect("telegram")} + /> + } + label="Discord" + onClick={() => onSelect("discord")} + /> + } label="Apple" disabled /> +
+
+ ); +}; diff --git a/sdk/oko_sdk_core/src/ui/signin_modal/hooks/use_theme.ts b/sdk/oko_sdk_core/src/ui/signin_modal/hooks/use_theme.ts new file mode 100644 index 000000000..131f71d3d --- /dev/null +++ b/sdk/oko_sdk_core/src/ui/signin_modal/hooks/use_theme.ts @@ -0,0 +1,74 @@ +import { useState, useEffect } from "preact/hooks"; + +import type { SignInModalTheme, ResolvedTheme } from "../types"; + +function getSystemTheme(): ResolvedTheme { + if ( + typeof window !== "undefined" && + window.matchMedia("(prefers-color-scheme: dark)").matches + ) { + return "dark"; + } + return "light"; +} + +function getHostTheme(): ResolvedTheme | null { + if (typeof document === "undefined") { + return null; + } + + const root = document.documentElement; + const body = document.body; + + const dataTheme = root.dataset.theme || body?.dataset.theme; + if (dataTheme === "dark" || dataTheme === "light") { + return dataTheme; + } + + if (root.classList.contains("dark") || body?.classList.contains("dark")) { + return "dark"; + } + if (root.classList.contains("light") || body?.classList.contains("light")) { + return "light"; + } + + const colorScheme = getComputedStyle(root).colorScheme; + if (colorScheme === "dark" || colorScheme === "light") { + return colorScheme; + } + + return null; +} + +export function resolveTheme(theme: SignInModalTheme): ResolvedTheme { + if (theme === "light" || theme === "dark") { + return theme; + } + return getHostTheme() ?? getSystemTheme(); +} + +export function useTheme(theme: SignInModalTheme): ResolvedTheme { + const [resolvedTheme, setResolvedTheme] = useState(() => + resolveTheme(theme), + ); + + useEffect(() => { + if (theme !== "system") { + setResolvedTheme(theme); + return; + } + + const updateTheme = () => { + setResolvedTheme(getHostTheme() ?? getSystemTheme()); + }; + + const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)"); + mediaQuery.addEventListener("change", updateTheme); + + return () => { + mediaQuery.removeEventListener("change", updateTheme); + }; + }, [theme]); + + return resolvedTheme; +} diff --git a/sdk/oko_sdk_core/src/ui/signin_modal/icons.ts b/sdk/oko_sdk_core/src/ui/signin_modal/icons.ts new file mode 100644 index 000000000..527d92bda --- /dev/null +++ b/sdk/oko_sdk_core/src/ui/signin_modal/icons.ts @@ -0,0 +1,12 @@ +const S3_BUCKET_URL = + "https://oko-wallet.s3.ap-northeast-2.amazonaws.com/icons"; + +export const S3_LOGO_URL = { + light: `${S3_BUCKET_URL}/oko_logo_light.png`, + dark: `${S3_BUCKET_URL}/oko_logo_dark.png`, +}; + +export const S3_LOGO_WITH_NAME_URL = { + light: `${S3_BUCKET_URL}/oko_logo_with_name_light.svg`, + dark: `${S3_BUCKET_URL}/oko_logo_with_name_dark.svg`, +}; diff --git a/sdk/oko_sdk_core/src/ui/signin_modal/index.ts b/sdk/oko_sdk_core/src/ui/signin_modal/index.ts new file mode 100644 index 000000000..61a212fae --- /dev/null +++ b/sdk/oko_sdk_core/src/ui/signin_modal/index.ts @@ -0,0 +1,2 @@ +export { renderSignInModal } from "./render"; +export type { SignInModalOptions, SignInModalTheme } from "./types"; diff --git a/sdk/oko_sdk_core/src/ui/signin_modal/render.tsx b/sdk/oko_sdk_core/src/ui/signin_modal/render.tsx new file mode 100644 index 000000000..1bb024efd --- /dev/null +++ b/sdk/oko_sdk_core/src/ui/signin_modal/render.tsx @@ -0,0 +1,54 @@ +import { render } from "preact"; + +import { SignInModal } from "./signin_modal"; +import { modalStyles } from "./styles"; +import { resolveTheme } from "./hooks/use_theme"; +import type { SignInModalOptions } from "./types"; + +const SIGNIN_MODAL_CONTAINER_ID = "oko-signin-modal-root"; + +export function renderSignInModal(options: SignInModalOptions) { + if (typeof document === "undefined") { + throw new Error("renderSignInModal cannot be called in SSR environment"); + } + + const { onSelect, onClose, theme = "system" } = options; + + const container = document.createElement("div"); + container.id = SIGNIN_MODAL_CONTAINER_ID; + container.dataset.theme = resolveTheme(theme); + + const shadow = container.attachShadow({ mode: "closed" }); + + const styleSheet = new CSSStyleSheet(); + styleSheet.replaceSync(modalStyles); + shadow.adoptedStyleSheets = [styleSheet]; + + const preactRoot = document.createElement("div"); + shadow.appendChild(preactRoot); + + const originalOverflow = document.body.style.overflow; + document.body.appendChild(container); + document.body.style.overflow = "hidden"; + + const cleanup = () => { + document.body.style.overflow = originalOverflow; + render(null, preactRoot); + container.remove(); + }; + + const handleClose = () => { + cleanup(); + onClose?.(); + }; + + const handleSelect = async (provider: Parameters[0]) => { + await onSelect(provider); + cleanup(); + }; + + render( + , + preactRoot, + ); +} diff --git a/sdk/oko_sdk_core/src/ui/signin_modal/signin_modal.tsx b/sdk/oko_sdk_core/src/ui/signin_modal/signin_modal.tsx new file mode 100644 index 000000000..23899a0cd --- /dev/null +++ b/sdk/oko_sdk_core/src/ui/signin_modal/signin_modal.tsx @@ -0,0 +1,106 @@ +import { type FunctionComponent as FC, type JSX } from "preact"; +import { useState, useEffect, useMemo } from "preact/hooks"; + +import type { SignInType } from "@oko-wallet-sdk-core/types/oauth"; +import type { SignInModalTheme, ProgressState } from "./types"; +import { useTheme } from "./hooks/use_theme"; +import { DefaultView } from "./components/default_view"; +import { SocialsView } from "./components/socials_view"; +import { ProgressView } from "./components/progress_view"; +import { CloseIcon } from "./components/icons"; + +export interface SignInModalProps { + onSelect: (provider: SignInType) => Promise; + onClose: () => void; + theme?: SignInModalTheme; +} + +type ViewType = "default" | "socials"; + +export const SignInModal: FC = ({ + onSelect, + onClose, + theme, +}) => { + const [view, setView] = useState("default"); + const [progress, setProgress] = useState(null); + const resolvedTheme = useTheme(theme || "system"); + + const handleSelect = async (provider: SignInType) => { + setProgress({ status: "loading", provider }); + try { + await onSelect(provider); + } catch { + setProgress({ status: "failed", provider }); + } + }; + + const handleRetry = () => { + setProgress(null); + setView("default"); + }; + + const handleOverlayClick = (e: JSX.TargetedMouseEvent) => { + if (e.target === e.currentTarget) { + onClose(); + } + }; + + useEffect(() => { + const handleKeyDown = (e: KeyboardEvent) => { + if (e.key === "Escape") { + onClose(); + } + }; + + document.addEventListener("keydown", handleKeyDown); + return () => { + document.removeEventListener("keydown", handleKeyDown); + }; + }, [onClose]); + + const content = useMemo(() => { + if (progress) { + return ( + + ); + } + + if (view === "socials") { + return ( + setView("default")} + /> + ); + } + + return ( + setView("socials")} + /> + ); + }, [progress, resolvedTheme, handleSelect]); + + return ( +
+
+ +
{content}
+
+
+ ); +}; diff --git a/sdk/oko_sdk_core/src/ui/signin_modal/styles.ts b/sdk/oko_sdk_core/src/ui/signin_modal/styles.ts new file mode 100644 index 000000000..c14f3e071 --- /dev/null +++ b/sdk/oko_sdk_core/src/ui/signin_modal/styles.ts @@ -0,0 +1,463 @@ +const css = String.raw; + +export const modalStyles = css` + :host { + /* Font */ + --oko-font-family: + Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; + + /* Colors - Light theme (from oko_common_ui color_tokens) */ + --oko-white: #ffffff; + --oko-gray-50: #fafafa; + --oko-gray-100: #f5f5f5; + --oko-gray-300: #d5d7da; + --oko-gray-400: #a4a7ae; + --oko-gray-500: #717680; + --oko-gray-600: #535862; + --oko-gray-700: #414651; + --oko-gray-900: #181d27; + --oko-gray-950: #0a0d12; + + /* Semantic tokens */ + --oko-bg-primary: var(--oko-white); + --oko-bg-primary-hover: var(--oko-gray-50); + --oko-bg-secondary: var(--oko-gray-50); + --oko-bg-tertiary: var(--oko-gray-100); + --oko-bg-overlay: var(--oko-gray-950); + --oko-text-primary: var(--oko-gray-900); + --oko-text-secondary: var(--oko-gray-700); + --oko-text-brand-secondary: var(--oko-gray-900); + --oko-fg-tertiary: var(--oko-gray-600); + --oko-fg-quaternary: var(--oko-gray-400); + --oko-fg-disabled-subtle: var(--oko-gray-300); + --oko-fg-brand-primary: var(--oko-gray-900); + --oko-border-primary: var(--oko-gray-300); + --oko-border-error-subtle: #fda29b; + + /* Shadows */ + --oko-shadow-xs: 0 1px 2px 0 rgba(16, 24, 40, 0.05); + --oko-shadow-lg: + 0 12px 16px -4px rgba(16, 24, 40, 0.08), + 0 4px 6px -2px rgba(16, 24, 40, 0.03); + + /* Spacing */ + --oko-spacing-xs: 4px; + --oko-radius-md: 8px; + --oko-radius-lg: 16px; + } + + /* Dark theme */ + :host([data-theme="dark"]) { + /* Colors - Dark theme (from oko_common_ui color_tokens) */ + --oko-gray-50: #f7f7f7; + --oko-gray-300: #cecfd2; + --oko-gray-400: #94979c; + --oko-gray-500: #85888e; + --oko-gray-600: #61656c; + --oko-gray-700: #373a41; + --oko-gray-800: #22262f; + --oko-gray-900: #13161b; + --oko-gray-950: #0c0e12; + + /* Semantic tokens - Dark */ + --oko-bg-primary: var(--oko-gray-950); + --oko-bg-primary-hover: var(--oko-gray-800); + --oko-bg-secondary: var(--oko-gray-900); + --oko-bg-tertiary: var(--oko-gray-800); + --oko-text-primary: var(--oko-gray-50); + --oko-text-secondary: var(--oko-gray-300); + --oko-text-brand-secondary: var(--oko-gray-300); + --oko-fg-tertiary: var(--oko-gray-400); + --oko-fg-quaternary: var(--oko-gray-600); + --oko-fg-disabled-subtle: var(--oko-gray-600); + --oko-fg-brand-primary: var(--oko-gray-50); + --oko-border-primary: var(--oko-gray-700); + --oko-border-error-subtle: #f04438; + + /* Shadows - Dark */ + --oko-shadow-xs: 0 1px 2px 0 rgba(0, 0, 0, 0.2); + --oko-shadow-lg: + 0 12px 16px -4px rgba(0, 0, 0, 0.3), 0 4px 6px -2px rgba(0, 0, 0, 0.2); + } + + * { + box-sizing: border-box; + margin: 0; + padding: 0; + } + + .oko-modal-overlay { + position: fixed; + top: 0; + left: 0; + width: 100vw; + height: 100vh; + background: rgba(0, 0, 0, 0.5); + display: flex; + justify-content: center; + align-items: center; + z-index: 2147483647; + isolation: isolate; + font-family: var(--oko-font-family); + } + + .oko-modal-container { + position: relative; + background: var(--oko-bg-primary); + border-radius: var(--oko-radius-lg); + box-shadow: var(--oko-shadow-lg); + width: 100%; + max-width: 400px; + margin: 16px; + overflow: hidden; + animation: oko-modal-fade-in 0.2s ease-out; + } + + @keyframes oko-modal-fade-in { + from { + opacity: 0; + transform: scale(0.95); + } + to { + opacity: 1; + transform: scale(1); + } + } + + .oko-modal-close { + position: absolute; + right: 24px; + top: 24px; + width: 36px; + height: 36px; + padding: var(--oko-radius-md); + border: none; + background: transparent; + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + border-radius: var(--oko-radius-md); + color: var(--oko-fg-tertiary); + transition: background-color 0.2s ease; + z-index: 1; + } + + .oko-modal-close:hover { + background: var(--oko-bg-secondary); + } + + .oko-modal-close svg { + width: 20px; + height: 20px; + } + + /* Progress View (Loading/Failed) */ + .oko-progress-view { + display: flex; + padding: 32px 24px 24px 24px; + flex-direction: column; + align-items: center; + justify-content: center; + min-height: 240px; + } + + .oko-progress-circle { + display: flex; + align-items: center; + justify-content: center; + width: 54px; + height: 54px; + position: relative; + } + + .oko-progress-circle .oko-provider-icon { + width: 48px; + height: 48px; + } + + .oko-progress-circle .oko-provider-icon svg { + width: 100%; + height: 100%; + } + + .oko-spinner-overlay { + position: absolute; + top: 50%; + left: 50%; + margin-top: -31px; + margin-left: -31px; + z-index: 10; + width: 62px; + height: 62px; + color: var(--oko-fg-brand-primary); + } + + .oko-spinner-overlay svg { + width: 100%; + height: 100%; + } + + .oko-spinner-overlay.oko-spinning svg { + animation: oko-spin 1s linear infinite; + } + + .oko-spinner-overlay:not(.oko-spinning) { + color: var(--oko-border-error-subtle); + } + + @keyframes oko-spin { + from { + transform: rotate(0deg); + } + to { + transform: rotate(360deg); + } + } + + .oko-progress-text { + margin-top: 9px; + font-size: 16px; + font-weight: 500; + line-height: 24px; + color: var(--oko-text-primary); + text-align: center; + } + + .oko-retry-btn { + display: flex; + height: 20px; + justify-content: center; + align-items: center; + gap: 4px; + align-self: stretch; + cursor: pointer; + margin-top: 16px; + background: none; + border: none; + font-family: var(--oko-font-family); + font-size: 14px; + font-weight: 600; + line-height: 20px; + color: var(--oko-text-brand-secondary); + } + + .oko-retry-btn:hover { + opacity: 0.8; + } + + /* Default View */ + .oko-default-view { + display: flex; + flex-direction: column; + align-items: center; + padding: 48px 20px 20px 20px; + } + + .oko-logo-wrapper { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + gap: 20px; + margin-bottom: 36px; + } + + .oko-logo-wrapper img { + display: block; + } + + /* Socials View */ + .oko-socials-view { + display: flex; + flex-direction: column; + align-items: center; + padding: 24px; + } + + .oko-back-row { + display: flex; + flex-direction: row; + align-items: center; + align-self: stretch; + margin-bottom: 26px; + } + + .oko-back-btn { + width: 24px; + height: 24px; + border: none; + background: transparent; + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + color: var(--oko-text-primary); + padding: 0; + } + + .oko-back-btn svg { + width: 24px; + height: 24px; + } + + .oko-back-title { + flex: 1; + text-align: center; + font-size: 14px; + font-weight: 500; + color: var(--oko-text-primary); + padding-right: 24px; /* Balance the back button */ + } + + /* Provider List */ + .oko-provider-list { + display: flex; + flex-direction: column; + gap: 16px; + width: 100%; + } + + .oko-socials-list { + gap: 12px; + } + + /* Provider Button */ + .oko-provider-btn { + display: flex; + justify-content: center; + align-items: center; + gap: var(--oko-spacing-xs); + width: 100%; + height: 40px; + padding: 10px 14px; + border: 1px solid var(--oko-border-primary); + border-radius: var(--oko-radius-md); + background: var(--oko-bg-primary); + cursor: pointer; + font-family: var(--oko-font-family); + font-size: 14px; + font-weight: 600; + line-height: 20px; + color: var(--oko-text-primary); + box-shadow: var(--oko-shadow-xs); + transition: background 0.2s ease; + outline: none; + } + + .oko-provider-btn:hover:not(:disabled) { + background: var(--oko-bg-primary-hover); + } + + .oko-provider-btn:focus { + box-shadow: + 0 0 0 4px rgba(152, 162, 179, 0.14), + 0 1px 2px 0 rgba(16, 24, 40, 0.05); + } + + .oko-provider-btn:disabled { + color: var(--oko-fg-quaternary); + border-color: var(--oko-fg-disabled-subtle); + cursor: not-allowed; + } + + .oko-provider-icon { + width: 20px; + height: 20px; + flex-shrink: 0; + display: flex; + align-items: center; + justify-content: center; + } + + .oko-provider-icon svg { + width: 100%; + height: 100%; + } + + .oko-provider-label { + padding: 0 2px; + } + + /* Social Icons Wrapper (for Other Socials button) */ + .oko-social-icons-wrapper { + display: flex; + align-items: center; + position: relative; + } + + .oko-social-icon { + width: 16px; + height: 16px; + display: flex; + align-items: center; + justify-content: center; + } + + .oko-social-icon + .oko-social-icon { + margin-left: -2px; + } + + .oko-social-icon svg { + width: 100%; + height: 100%; + } + + .oko-chevron-icon { + width: 20px; + height: 20px; + display: flex; + align-items: center; + justify-content: center; + color: var(--oko-fg-quaternary); + } + + .oko-chevron-icon svg { + width: 100%; + height: 100%; + } + + /* Footer */ + .oko-modal-footer { + margin-top: 28px; + display: flex; + justify-content: space-between; + align-items: center; + width: 100%; + } + + .oko-footer-logo { + display: block; + width: 52px; + height: 20px; + } + + .oko-footer-link { + font-size: 12px; + font-weight: 500; + color: var(--oko-text-secondary); + text-decoration: underline; + display: flex; + align-items: center; + gap: 4px; + cursor: pointer; + } + + .oko-footer-link:hover { + color: var(--oko-text-primary); + } + + .oko-external-icon { + width: 16px; + height: 16px; + display: flex; + align-items: center; + justify-content: center; + color: var(--oko-gray-500); + } + + .oko-external-icon svg { + width: 100%; + height: 100%; + } +`; diff --git a/sdk/oko_sdk_core/src/ui/signin_modal/types.ts b/sdk/oko_sdk_core/src/ui/signin_modal/types.ts new file mode 100644 index 000000000..25106aa4d --- /dev/null +++ b/sdk/oko_sdk_core/src/ui/signin_modal/types.ts @@ -0,0 +1,15 @@ +import type { SignInType } from "@oko-wallet-sdk-core/types/oauth"; + +export type SignInModalTheme = "light" | "dark" | "system"; +export type ResolvedTheme = "light" | "dark"; + +export interface SignInModalOptions { + onSelect: (provider: SignInType) => Promise; + onClose?: () => void; + theme?: SignInModalTheme; +} + +export interface ProgressState { + status: "loading" | "failed"; + provider: SignInType; +} diff --git a/sdk/oko_sdk_core/tsconfig.json b/sdk/oko_sdk_core/tsconfig.json index b015ac2b5..05186149e 100644 --- a/sdk/oko_sdk_core/tsconfig.json +++ b/sdk/oko_sdk_core/tsconfig.json @@ -3,6 +3,8 @@ "target": "ES2020", "module": "ESNext", "moduleResolution": "bundler", + "jsx": "react-jsx", + "jsxImportSource": "preact", "lib": ["dom", "ES2020", "ESNext.AsyncIterable"], "skipLibCheck": true, "sourceMap": true, diff --git a/sdk/oko_sdk_sol/src/wallet-standard/wallet.ts b/sdk/oko_sdk_sol/src/wallet-standard/wallet.ts index 98ac11590..158d1cfdc 100644 --- a/sdk/oko_sdk_sol/src/wallet-standard/wallet.ts +++ b/sdk/oko_sdk_sol/src/wallet-standard/wallet.ts @@ -65,7 +65,7 @@ export class OkoStandardWallet implements Wallet { if (!existingKey) { // Trigger OAuth sign-in - await this.#wallet.okoWallet.signIn("google"); + await this.#wallet.okoWallet.openSignInModal(); // Re-check after sign-in existingKey = await this.#wallet.okoWallet.getPublicKeyEd25519(); diff --git a/yarn.lock b/yarn.lock index a97c802d3..6048684c4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10916,6 +10916,7 @@ __metadata: chalk: "npm:^5.5.0" del: "npm:^8.0.1" jest: "npm:^30.1.3" + preact: "npm:^10.25.4" rollup: "npm:^4.0.0" rollup-plugin-dts: "npm:^6.2.1" rollup-plugin-tsconfig-paths: "npm:^1.5.2" @@ -35860,6 +35861,13 @@ __metadata: languageName: node linkType: hard +"preact@npm:^10.25.4": + version: 10.28.2 + resolution: "preact@npm:10.28.2" + checksum: 10c0/eb60bf526eb6971701e6ac9c25236aca451f17f99e9c24704419196989b15bb576ed3101e084b151cd0fb30546b3e5e1ba73b774e8be2f2ed8187db42ec65faf + languageName: node + linkType: hard + "prelude-ls@npm:^1.2.1": version: 1.2.1 resolution: "prelude-ls@npm:1.2.1" From b20fe5ae80cfe08af3fd6bf21e53f0070eb2f18b Mon Sep 17 00:00:00 2001 From: Elden Park Date: Mon, 12 Jan 2026 19:23:00 -0800 Subject: [PATCH 2/5] crypto/teddsa: compute "verifying keyshare" from "signing share" * teddsa: add tc to check identifier * teddsa: add scalar multiplication functionality for Ed25519 keys * ci: streamline wasm copy process by ensuring successful execution * teddsa: implement TeddsaKeyShare interface and serialization functions * attached: add computeVerifyingShare function * attached: implement split and combine functions Co-authored-by: Atmosis --- common/oko_types/src/user_key_share/index.ts | 102 ++++- .../tests/integration_tests.rs | 150 ++++++ .../wasm/src/keys/mod.rs | 2 + .../wasm/src/keys/scalar_mult.rs | 78 ++++ embed/oko_attached/src/crypto/scalar.ts | 35 ++ embed/oko_attached/src/crypto/sss_ed25519.ts | 428 ++++++++---------- internals/ci/src/cmds/build_frost.ts | 13 +- key_share_node/ksn_interface/src/key_share.ts | 21 + 8 files changed, 580 insertions(+), 249 deletions(-) create mode 100644 crypto/teddsa/frost_ed25519_keplr_wasm/wasm/src/keys/scalar_mult.rs create mode 100644 embed/oko_attached/src/crypto/scalar.ts diff --git a/common/oko_types/src/user_key_share/index.ts b/common/oko_types/src/user_key_share/index.ts index eae42744d..4e08e3e4f 100644 --- a/common/oko_types/src/user_key_share/index.ts +++ b/common/oko_types/src/user_key_share/index.ts @@ -1,4 +1,4 @@ -import type { Bytes32 } from "@oko-wallet/bytes"; +import { Bytes, type Bytes32, type Bytes64 } from "@oko-wallet/bytes"; export interface RunExpandSharesResult { t: number; @@ -24,3 +24,103 @@ 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, + }; +} diff --git a/crypto/teddsa/frost_ed25519_keplr/tests/integration_tests.rs b/crypto/teddsa/frost_ed25519_keplr/tests/integration_tests.rs index 77bb73716..8f53095a4 100644 --- a/crypto/teddsa/frost_ed25519_keplr/tests/integration_tests.rs +++ b/crypto/teddsa/frost_ed25519_keplr/tests/integration_tests.rs @@ -379,3 +379,153 @@ 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" + ); + } +} diff --git a/crypto/teddsa/frost_ed25519_keplr_wasm/wasm/src/keys/mod.rs b/crypto/teddsa/frost_ed25519_keplr_wasm/wasm/src/keys/mod.rs index a14896e17..c1d6cbee6 100644 --- a/crypto/teddsa/frost_ed25519_keplr_wasm/wasm/src/keys/mod.rs +++ b/crypto/teddsa/frost_ed25519_keplr_wasm/wasm/src/keys/mod.rs @@ -1,7 +1,9 @@ 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::*; diff --git a/crypto/teddsa/frost_ed25519_keplr_wasm/wasm/src/keys/scalar_mult.rs b/crypto/teddsa/frost_ed25519_keplr_wasm/wasm/src/keys/scalar_mult.rs new file mode 100644 index 000000000..d23c78d14 --- /dev/null +++ b/crypto/teddsa/frost_ed25519_keplr_wasm/wasm/src/keys/scalar_mult.rs @@ -0,0 +1,78 @@ +use curve25519_dalek::constants::ED25519_BASEPOINT_TABLE; +use curve25519_dalek::scalar::Scalar; +use gloo_utils::format::JsValueSerdeExt; +use serde::{Deserialize, Serialize}; +use wasm_bindgen::prelude::*; + +#[derive(Serialize, Deserialize)] +pub struct ScalarBaseMultInput { + pub scalar: Vec, +} + +#[derive(Serialize, Deserialize)] +pub struct ScalarBaseMultOutput { + pub point: Vec, +} + +/// Compute verifying_share (point) from signing_share (scalar). +/// verifying_share = signing_share * G (Ed25519 base point) +#[wasm_bindgen] +pub fn scalar_base_mult(input: JsValue) -> Result { + let input: ScalarBaseMultInput = input + .into_serde() + .map_err(|e| JsValue::from_str(&format!("Failed to parse input: {}", e)))?; + + let result = + scalar_base_mult_inner(&input).map_err(|e| JsValue::from_str(&format!("{}", e)))?; + + JsValue::from_serde(&result) + .map_err(|e| JsValue::from_str(&format!("Failed to serialize output: {}", e))) +} + +fn scalar_base_mult_inner(input: &ScalarBaseMultInput) -> Result { + if input.scalar.len() != 32 { + return Err(format!( + "Invalid scalar length: expected 32, got {}", + input.scalar.len() + )); + } + + let scalar_bytes: [u8; 32] = input + .scalar + .clone() + .try_into() + .map_err(|_| "Failed to convert scalar bytes")?; + + let scalar = Scalar::from_bytes_mod_order(scalar_bytes); + let point = &scalar * ED25519_BASEPOINT_TABLE; + let point_bytes = point.compress().to_bytes(); + + Ok(ScalarBaseMultOutput { + point: point_bytes.to_vec(), + }) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_scalar_base_mult_valid() { + let mut scalar = vec![0u8; 32]; + scalar[0] = 1; + + let input = ScalarBaseMultInput { scalar }; + let result = scalar_base_mult_inner(&input).unwrap(); + + assert_eq!(result.point.len(), 32); + } + + #[test] + fn test_scalar_base_mult_invalid_length() { + let input = ScalarBaseMultInput { + scalar: vec![1u8; 16], + }; + let result = scalar_base_mult_inner(&input); + assert!(result.is_err()); + } +} diff --git a/embed/oko_attached/src/crypto/scalar.ts b/embed/oko_attached/src/crypto/scalar.ts new file mode 100644 index 000000000..752a1d85b --- /dev/null +++ b/embed/oko_attached/src/crypto/scalar.ts @@ -0,0 +1,35 @@ +import type { Bytes32 } from "@oko-wallet/bytes"; +import { Bytes } from "@oko-wallet/bytes"; +import { wasmModule } from "@oko-wallet/frost-ed25519-keplr-wasm"; + +interface TeddsaScalarBaseMultInput { + scalar: number[]; +} + +interface TeddsaScalarBaseMultOutput { + point: number[]; +} + +/** + * Compute verifying_share from signing_share. + * Ed25519: verifying_share = signing_share * G (base point) + * + * Used to reconstruct KeyPackage from SSS-recovered signing_share. + * + * @param signingShare - 32-byte signing_share + * @returns 32-byte verifying_share (compressed Ed25519 point) + */ +export function computeVerifyingShare(signingShare: Bytes32): Bytes32 { + const input: TeddsaScalarBaseMultInput = { + scalar: Array.from(signingShare.toUint8Array()), + }; + + const output: TeddsaScalarBaseMultOutput = wasmModule.scalar_base_mult(input); + + const result = Bytes.fromUint8Array(new Uint8Array(output.point), 32); + if (!result.success) { + throw new Error(`Invalid verifying_share output: ${result.err}`); + } + + return result.data; +} diff --git a/embed/oko_attached/src/crypto/sss_ed25519.ts b/embed/oko_attached/src/crypto/sss_ed25519.ts index d1c0b9476..50d375fad 100644 --- a/embed/oko_attached/src/crypto/sss_ed25519.ts +++ b/embed/oko_attached/src/crypto/sss_ed25519.ts @@ -1,241 +1,187 @@ -// refactor this file @chemonoworld - -// import type { KeyShareNodeMetaWithNodeStatusInfo } from "@oko-wallet/oko-types/tss"; -// import { wasmModule } from "@oko-wallet/frost-ed25519-keplr-wasm"; -// import { Bytes, type Bytes32 } from "@oko-wallet/bytes"; -// import type { -// PointNumArr, -// UserKeySharePointByNode, -// } from "@oko-wallet/oko-types/user_key_share"; -// import type { TeddsaKeygenOutputBytes } from "@oko-wallet/teddsa-hooks"; -// import type { Result } from "@oko-wallet/stdlib-js"; - -// import { hashKeyshareNodeNamesEd25519 } from "./hash"; - -// /** -// * Data structure for Ed25519 key share backup on KS nodes. -// * Contains the SSS split of signing_share along with public info needed for reconstruction. -// */ -// export interface Ed25519KeyShareBackup { -// /** SSS split point (x: identifier, y: share) */ -// share: { -// x: Bytes32; -// y: Bytes32; -// }; -// /** Serialized PublicKeyPackage (needed for reconstruction) */ -// publicKeyPackage: string; // hex string -// /** Participant identifier (needed for reconstruction) */ -// identifier: string; // hex string -// /** Ed25519 public key (for verification) */ -// publicKey: string; // hex string -// } - -// /** -// * Split Ed25519 key package for backup on Key Share Nodes. -// * -// * Extracts the signing_share from the key_package and splits it using SSS. -// * Also includes the public information needed to reconstruct the key_package. -// */ -// export async function splitUserKeySharesEd25519( -// keygen_1: TeddsaKeygenOutputBytes, -// keyshareNodeMeta: KeyShareNodeMetaWithNodeStatusInfo, -// ): Promise> { -// try { -// const keyPackageBytes = [...keygen_1.key_package]; - -// // Extract signing_share from key_package (32-byte scalar) -// const signingShareArr: number[] = -// wasmModule.extract_signing_share(keyPackageBytes); - -// // Hash KS node names to get identifiers for SSS (Ed25519-compatible) -// const keyshareNodeHashesRes = await hashKeyshareNodeNamesEd25519( -// keyshareNodeMeta.nodes.map((meta) => meta.name), -// ); -// if (keyshareNodeHashesRes.success === false) { -// return { -// success: false, -// err: keyshareNodeHashesRes.err, -// }; -// } -// const keyshareNodeHashes = keyshareNodeHashesRes.data.map((bytes) => { -// return [...bytes.toUint8Array()]; -// }); - -// // Split signing_share using SSS -// const splitPoints: PointNumArr[] = wasmModule.sss_split( -// signingShareArr, -// keyshareNodeHashes, -// keyshareNodeMeta.threshold, -// ); - -// // Convert to UserKeySharePointByNode format -// const shares: UserKeySharePointByNode[] = splitPoints.map( -// (point: PointNumArr, index: number) => { -// const xBytesRes = Bytes.fromUint8Array( -// Uint8Array.from([...point.x]), -// 32, -// ); -// if (xBytesRes.success === false) { -// throw new Error(xBytesRes.err); -// } -// const yBytesRes = Bytes.fromUint8Array( -// Uint8Array.from([...point.y]), -// 32, -// ); -// if (yBytesRes.success === false) { -// throw new Error(yBytesRes.err); -// } -// return { -// node: { -// name: keyshareNodeMeta.nodes[index].name, -// endpoint: keyshareNodeMeta.nodes[index].endpoint, -// }, -// share: { -// x: xBytesRes.data, -// y: yBytesRes.data, -// }, -// }; -// }, -// ); - -// return { -// success: true, -// data: shares, -// }; -// } catch (error: any) { -// return { -// success: false, -// err: `splitUserKeySharesEd25519 failed: ${String(error)}`, -// }; -// } -// } - -// /** -// * Combine Ed25519 key shares to recover the signing_share. -// */ -// export async function combineUserSharesEd25519( -// userKeySharePoints: UserKeySharePointByNode[], -// threshold: number, -// ): Promise> { -// try { -// if (threshold < 2) { -// return { -// success: false, -// err: "Threshold must be at least 2", -// }; -// } - -// if (userKeySharePoints.length < threshold) { -// return { -// success: false, -// err: "Number of user key shares is less than threshold", -// }; -// } - -// const points: PointNumArr[] = userKeySharePoints.map( -// (userKeySharePoint) => ({ -// x: [...userKeySharePoint.share.x.toUint8Array()], -// y: [...userKeySharePoint.share.y.toUint8Array()], -// }), -// ); - -// // Combine shares to recover signing_share -// const combinedSigningShare: number[] = wasmModule.sss_combine( -// points, -// threshold, -// ); - -// return { -// success: true, -// data: Uint8Array.from(combinedSigningShare), -// }; -// } catch (e) { -// return { -// success: false, -// err: `combineUserSharesEd25519 failed: ${String(e)}`, -// }; -// } -// } - -// /** -// * Reconstruct a full KeyPackage from a recovered signing_share and public info. -// */ -// export async function reconstructKeyPackageEd25519( -// signingShare: Uint8Array, -// publicKeyPackage: Uint8Array, -// identifier: Uint8Array, -// ): Promise> { -// try { -// const keyPackageArr: number[] = wasmModule.reconstruct_key_package( -// [...signingShare], -// [...publicKeyPackage], -// [...identifier], -// ); - -// return { -// success: true, -// data: Uint8Array.from(keyPackageArr), -// }; -// } catch (e) { -// return { -// success: false, -// err: `reconstructKeyPackageEd25519 failed: ${String(e)}`, -// }; -// } -// } - -// /** -// * Full recovery of Ed25519 keygen output from KS node shares. -// * -// * Given the SSS shares from KS nodes plus the stored public info, -// * reconstructs the complete TeddsaKeygenOutputBytes. -// */ -// export async function recoverEd25519Keygen( -// userKeySharePoints: UserKeySharePointByNode[], -// threshold: number, -// publicKeyPackage: Uint8Array, -// identifier: Uint8Array, -// publicKey: Bytes32, -// ): Promise> { -// try { -// // Combine shares to recover signing_share -// const combineRes = await combineUserSharesEd25519( -// userKeySharePoints, -// threshold, -// ); -// if (!combineRes.success) { -// return { -// success: false, -// err: combineRes.err, -// }; -// } - -// // Reconstruct key_package from signing_share + public info -// const reconstructRes = await reconstructKeyPackageEd25519( -// combineRes.data, -// publicKeyPackage, -// identifier, -// ); -// if (!reconstructRes.success) { -// return { -// success: false, -// err: reconstructRes.err, -// }; -// } - -// return { -// success: true, -// data: { -// key_package: reconstructRes.data, -// public_key_package: publicKeyPackage, -// identifier: identifier, -// public_key: publicKey, -// }, -// }; -// } catch (e) { -// return { -// success: false, -// err: `recoverEd25519Keygen failed: ${String(e)}`, -// }; -// } -// } +import type { KeyShareNodeMetaWithNodeStatusInfo } from "@oko-wallet/oko-types/tss"; +import { wasmModule } from "@oko-wallet/frost-ed25519-keplr-wasm"; +import { Bytes, type Bytes32 } from "@oko-wallet/bytes"; +import type { TeddsaKeyShareByNode } from "@oko-wallet/oko-types/user_key_share"; +import type { Result } from "@oko-wallet/stdlib-js"; +import type { + KeyPackage, + KeyPackageRaw, + PublicKeyPackageRaw, +} from "@oko-wallet/teddsa-interface"; + +import { hashKeyshareNodeNamesEd25519 } from "./hash"; +import { computeVerifyingShare } from "./scalar"; + +interface SplitOutputRaw { + key_packages: KeyPackageRaw[]; + public_key_package: PublicKeyPackageRaw; +} + +/** + * Split client signing_share using SSS for KS node distribution. + * + * Uses FROST's sss_split to split the signing_share. + * Extracts identifier and signing_share from each KeyPackage. + * + * @param signingShare - FROST KeyPackage's signing_share (32 bytes) + * @param keyshareNodeMeta - KS Node metadata (nodes, threshold) + * @returns TeddsaKeyShareByNode[] - (identifier, signing_share) pairs per node + */ +export async function splitTeddsaSigningShare( + signingShare: Bytes32, + keyshareNodeMeta: KeyShareNodeMetaWithNodeStatusInfo, +): Promise> { + try { + const signingShareArr = [...signingShare.toUint8Array()]; + + const identifiersRes = await hashKeyshareNodeNamesEd25519( + keyshareNodeMeta.nodes.map((n) => n.name), + ); + if (!identifiersRes.success) { + return { success: false, err: identifiersRes.err }; + } + + const identifiers = identifiersRes.data.map((b) => [...b.toUint8Array()]); + + const splitOutput: SplitOutputRaw = wasmModule.sss_split( + signingShareArr, + identifiers, + keyshareNodeMeta.threshold, + ); + + const shares: TeddsaKeyShareByNode[] = splitOutput.key_packages.map( + (kp, i) => { + const idBytes = Bytes.fromUint8Array( + new Uint8Array(kp.identifier), + 32, + ); + const shareBytes = Bytes.fromUint8Array( + new Uint8Array(kp.signing_share), + 32, + ); + + if (!idBytes.success) throw new Error(idBytes.err); + if (!shareBytes.success) throw new Error(shareBytes.err); + + return { + node: { + name: keyshareNodeMeta.nodes[i].name, + endpoint: keyshareNodeMeta.nodes[i].endpoint, + }, + share: { + identifier: idBytes.data, + signing_share: shareBytes.data, + }, + }; + }, + ); + + return { success: true, data: shares }; + } catch (e) { + return { + success: false, + err: `splitTeddsaSigningShare failed: ${String(e)}`, + }; + } +} + +/** + * Combine shares from KS nodes to recover signing_share. + * + * Converts TeddsaKeyShares to KeyPackageRaw format for sss_combine. + * + * @param shares - TeddsaKeyShare array from KS nodes + * @param threshold - SSS threshold (minimum shares required) + * @param verifyingKey - PublicKeyPackage's verifying_key (needed for KeyPackageRaw) + * @returns signing_share (32 bytes) + */ +export async function combineTeddsaShares( + shares: TeddsaKeyShareByNode[], + threshold: number, + verifyingKey: Bytes32, +): Promise> { + try { + if (shares.length < threshold) { + return { + success: false, + err: `Not enough shares: got ${shares.length}, need ${threshold}`, + }; + } + + const keyPackages: KeyPackageRaw[] = shares.map((s) => { + const verifyingShare = computeVerifyingShare(s.share.signing_share); + + return { + identifier: [...s.share.identifier.toUint8Array()], + signing_share: [...s.share.signing_share.toUint8Array()], + verifying_share: [...verifyingShare.toUint8Array()], + verifying_key: [...verifyingKey.toUint8Array()], + min_signers: threshold, + }; + }); + + const combined: number[] = wasmModule.sss_combine(keyPackages); + + const result = Bytes.fromUint8Array(Uint8Array.from(combined), 32); + if (!result.success) { + return { success: false, err: result.err }; + } + + return { success: true, data: result.data }; + } catch (e) { + return { success: false, err: `combineTeddsaShares failed: ${String(e)}` }; + } +} + +/** + * Reconstruct KeyPackage from recovered signing_share. + * + * Computes verifying_share from signing_share to create complete KeyPackage. + * + * @param signingShare - SSS-recovered client signing_share + * @param frostIdentifier - FROST P0 identifier (client is always 1) + * @param verifyingKey - PublicKeyPackage's verifying_key + * @param minSigners - threshold (2 for 2-of-2) + * @returns Complete FROST KeyPackage + */ +export function reconstructKeyPackage( + signingShare: Bytes32, + frostIdentifier: Bytes32, + verifyingKey: Bytes32, + minSigners: number, +): KeyPackage { + const verifyingShare = computeVerifyingShare(signingShare); + + return { + identifier: frostIdentifier, + signing_share: signingShare, + verifying_share: verifyingShare, + verifying_key: verifyingKey, + min_signers: minSigners, + }; +} + +/** + * Extract signing_share from KeyPackageRaw. + */ +export function extractSigningShare( + keyPackage: KeyPackageRaw, +): Result { + const signingShareRes = Bytes.fromUint8Array( + new Uint8Array(keyPackage.signing_share), + 32, + ); + if (!signingShareRes.success) { + return { success: false, err: signingShareRes.err }; + } + return { success: true, data: signingShareRes.data }; +} + +/** + * Extract signing_share from KeyPackage (Bytes type). + */ +export function extractSigningShareFromKeyPackage( + keyPackage: KeyPackage, +): Bytes32 { + return keyPackage.signing_share; +} diff --git a/internals/ci/src/cmds/build_frost.ts b/internals/ci/src/cmds/build_frost.ts index 9aea276b8..d8ea8c02d 100644 --- a/internals/ci/src/cmds/build_frost.ts +++ b/internals/ci/src/cmds/build_frost.ts @@ -14,11 +14,10 @@ export async function buildFrost(..._args: any[]) { expectSuccess(wasmRet, "wasm build failed"); console.log("%s %s", chalk.bold.green("Done"), "build wasm frost keplr"); - // TODO: copy wasm to oko_attached or other target locations @chemonoworld - // const copyRet = spawnSync("yarn", ["run", "copy_wasm"], { - // cwd: paths.oko_attached, - // stdio: "inherit", - // }); - // expectSuccess(copyRet, "copy failed"); - // console.log("%s %s", chalk.bold.green("Done"), "copy wasm"); + const copyRet = spawnSync("yarn", ["run", "copy_wasm"], { + cwd: paths.oko_attached, + stdio: "inherit", + }); + expectSuccess(copyRet, "copy failed"); + console.log("%s %s", chalk.bold.green("Done"), "copy wasm"); } diff --git a/key_share_node/ksn_interface/src/key_share.ts b/key_share_node/ksn_interface/src/key_share.ts index 88b3e2d1a..e827295ed 100644 --- a/key_share_node/ksn_interface/src/key_share.ts +++ b/key_share_node/ksn_interface/src/key_share.ts @@ -27,6 +27,21 @@ export type UpdateKeyShareRequest = { status: KeyShareStatus; }; +/** + * Key share registration request for KS node. + * + * Share format by curve_type (both are 64 bytes): + * + * secp256k1: + * Point256 { x: 32 bytes, y: 32 bytes } + * - Elliptic curve point coordinates + * + * ed25519 (TEDDSA): + * TeddsaKeyShare { identifier: 32 bytes, signing_share: 32 bytes } + * - identifier: SSS x-coordinate (node_name SHA256 hash, byte[31] &= 0x0F) + * - signing_share: SSS y-coordinate (split signing share) + * - Note: verifying_share is recovered from signing_share via scalar_base_mult + */ export interface RegisterKeyShareRequest { user_auth_id: string; auth_type: AuthType; @@ -76,6 +91,12 @@ export interface CheckKeyShareRequestBody { public_key: string; // hex string } +/** + * Key share reshare request for KS node. + * + * Share format is same as RegisterKeyShareRequest (64 bytes). + * See RegisterKeyShareRequest for detailed format by curve_type. + */ export interface ReshareKeyShareRequest { user_auth_id: string; auth_type: AuthType; From 845dea1fbb1dbe4209e9b0ec1d85b448fe26ea59 Mon Sep 17 00:00:00 2001 From: Chihun Park <61782539+chihunmanse@users.noreply.github.com> Date: Tue, 13 Jan 2026 14:18:27 +0900 Subject: [PATCH 3/5] tss_api: refactor ed25519 sign (hooks, addon) * teddsa_addon: add extractKeyPackageSharesEd25519 * tss_api: refactor Ed25519 keygen to store only signing/verifying shares * tss_api: refactor keygen test * tss_api: refactor presign_ed25519 * tss_api: add Ed25519 presign test * tss_api: refactor sign_ed25519 * teddsa_addon: add reconstruct_public_key_package * teddsa_addon: add reconstruct_public_key_package test * teddsa_addon: add reconstruct_key_package test * tss_api: refactor sign_ed25519_aggregate * tss_api: refactor sign_ed25519 test * tss_api: refactor sign ed25519 * tss_api: remove presign ed25519 * tss_api: refactor sign ed25519 stage * teddsa_hooks: refactor runTeddsaSign * tss_api: refactor wallet ed25519 --- .../src/api/keygen_ed25519/index.test.ts | 78 +- .../tss_api/src/api/keygen_ed25519/index.ts | 23 +- .../tss_api/src/api/presign_ed25519/index.ts | 116 -- .../src/api/sign_ed25519/index.test.ts | 1579 +++++++++-------- backend/tss_api/src/api/sign_ed25519/index.ts | 248 +-- .../tss_api/src/api/wallet_ed25519/index.ts | 39 +- backend/tss_api/src/routes/index.ts | 2 - backend/tss_api/src/routes/presign_ed25519.ts | 129 -- backend/tss_api/src/routes/sign_ed25519.ts | 56 +- backend/tss_api/src/routes/wallet_ed25519.ts | 22 +- common/oko_types/src/tss/sign_ed25519.ts | 35 +- common/oko_types/src/tss/tss_stage.ts | 10 +- crypto/teddsa/api_lib/src/index.ts | 34 - crypto/teddsa/api_lib/tsconfig.json | 17 +- crypto/teddsa/teddsa_addon/addon/index.d.ts | 11 + crypto/teddsa/teddsa_addon/addon/index.js | 5 +- .../teddsa/teddsa_addon/addon/src/keygen.rs | 169 +- .../addon/teddsa-addon.darwin-arm64.node | Bin 796304 -> 832000 bytes .../teddsa/teddsa_addon/src/server/index.ts | 50 + .../teddsa_addon/src/tests/keygen.test.ts | 567 +++++- crypto/teddsa/teddsa_hooks/package.json | 1 + crypto/teddsa/teddsa_hooks/src/sign.ts | 133 ++ embed/oko_attached/src/crypto/sign_ed25519.ts | 253 +-- yarn.lock | 3 +- 24 files changed, 2228 insertions(+), 1352 deletions(-) delete mode 100644 backend/tss_api/src/api/presign_ed25519/index.ts delete mode 100644 backend/tss_api/src/routes/presign_ed25519.ts diff --git a/backend/tss_api/src/api/keygen_ed25519/index.test.ts b/backend/tss_api/src/api/keygen_ed25519/index.test.ts index c748e8d24..a48a402eb 100644 --- a/backend/tss_api/src/api/keygen_ed25519/index.test.ts +++ b/backend/tss_api/src/api/keygen_ed25519/index.test.ts @@ -5,9 +5,14 @@ import { runKeygenCentralizedEd25519 } from "@oko-wallet/teddsa-addon/src/server import { createPgConn } from "@oko-wallet/postgres-lib"; import { insertKSNode } from "@oko-wallet/oko-pg-interface/ks_nodes"; import { createUser } from "@oko-wallet/oko-pg-interface/oko_users"; -import { createWallet } from "@oko-wallet/oko-pg-interface/oko_wallets"; +import { + createWallet, + getWalletById, +} from "@oko-wallet/oko-pg-interface/oko_wallets"; import { insertKeyShareNodeMeta } from "@oko-wallet/oko-pg-interface/key_share_node_meta"; import type { WalletStatus } from "@oko-wallet/oko-types/wallets"; +import { decryptDataAsync } from "@oko-wallet/crypto-js/node"; +import { extractKeyPackageSharesEd25519 } from "@oko-wallet/teddsa-addon/src/server"; import { resetPgDatabase } from "@oko-wallet-tss-api/testing/database"; import { testPgConfig } from "@oko-wallet-tss-api/database/test_config"; @@ -106,6 +111,12 @@ describe("Ed25519 Keygen", () => { TEMP_ENC_SECRET, ); + if (!result.success) { + console.error("Keygen failed:", { + code: result.code, + msg: result.msg, + }); + } expect(result.success).toBe(true); if (result.success) { expect(result.data.token).toBeDefined(); @@ -342,5 +353,70 @@ describe("Ed25519 Keygen", () => { // In production, the user_id would come from the database } }); + + it("should store only signing_share and verifying_share in enc_tss_share", async () => { + await setUpKSNodes(pool); + await setUpKeyShareNodeMeta(pool); + + const keygenResult = runKeygenCentralizedEd25519(); + const serverKeygenOutput = keygenResult.keygen_outputs[Participant.P1]; + + // Extract expected shares from server key_package + const expectedShares = extractKeyPackageSharesEd25519( + new Uint8Array(serverKeygenOutput.key_package), + ); + + const request = generateKeygenRequest(keygenResult); + + const result = await runKeygenEd25519( + pool, + TEST_JWT_CONFIG, + request, + TEMP_ENC_SECRET, + ); + + expect(result.success).toBe(true); + if (result.success) { + // Get wallet from database using wallet_id from result + const getWalletRes = await getWalletById( + pool, + result.data.user.wallet_id, + ); + expect(getWalletRes.success).toBe(true); + if (getWalletRes.success && getWalletRes.data) { + const wallet = getWalletRes.data; + + // Decrypt enc_tss_share + const encryptedShare = wallet.enc_tss_share.toString("utf-8"); + const decryptedShare = await decryptDataAsync( + encryptedShare, + TEMP_ENC_SECRET, + ); + const storedShares = JSON.parse(decryptedShare) as { + signing_share: number[]; + verifying_share: number[]; + }; + + // Verify structure: should only have signing_share and verifying_share + expect(storedShares).toHaveProperty("signing_share"); + expect(storedShares).toHaveProperty("verifying_share"); + expect(storedShares).not.toHaveProperty("key_package"); + expect(storedShares).not.toHaveProperty("public_key_package"); + expect(storedShares).not.toHaveProperty("identifier"); + + // Verify sizes: each should be 32 bytes + expect(storedShares.signing_share).toHaveLength(32); + expect(storedShares.verifying_share).toHaveLength(32); + + // Verify values match expected shares + expect(storedShares.signing_share).toEqual( + expectedShares.signing_share, + ); + expect(storedShares.verifying_share).toEqual( + expectedShares.verifying_share, + ); + } + } + }); }); }); diff --git a/backend/tss_api/src/api/keygen_ed25519/index.ts b/backend/tss_api/src/api/keygen_ed25519/index.ts index dabfdd221..30eca01d3 100644 --- a/backend/tss_api/src/api/keygen_ed25519/index.ts +++ b/backend/tss_api/src/api/keygen_ed25519/index.ts @@ -21,6 +21,7 @@ import { import { getKeyShareNodeMeta } from "@oko-wallet/oko-pg-interface/key_share_node_meta"; import { generateUserToken } from "@oko-wallet-tss-api/api/keplr_auth"; +import { extractKeyPackageSharesEd25519 } from "@oko-wallet/teddsa-addon/src/server"; export async function runKeygenEd25519( db: Pool, @@ -114,10 +115,7 @@ export async function runKeygenEd25519( }; } - // Ed25519 uses 2-of-2 threshold signature with server, not SSS key share - // nodes - // Skip checkKeyShareFromKSNodes validation (which expects secp256k1 - // 33-byte keys) + // TODO: Add KS node check after SSS & KSN logic is implemented const getActiveKSNodesRes = await getActiveKSNodes(db); if (getActiveKSNodesRes.success === false) { return { @@ -129,14 +127,19 @@ export async function runKeygenEd25519( const activeKSNodes = getActiveKSNodesRes.data; const ksNodeIds: string[] = activeKSNodes.map((node) => node.node_id); - const keyPackageJson = JSON.stringify({ - key_package: keygen_2.key_package, - public_key_package: keygen_2.public_key_package, - identifier: keygen_2.identifier, - }); + // Extract signing_share and verifying_share from key_package + const keyPackageShares = extractKeyPackageSharesEd25519( + new Uint8Array(keygen_2.key_package), + ); + + // Store only signing_share and verifying_share (64 bytes total) + const sharesData = { + signing_share: keyPackageShares.signing_share, + verifying_share: keyPackageShares.verifying_share, + }; const encryptedShare = await encryptDataAsync( - keyPackageJson, + JSON.stringify(sharesData), encryptionSecret, ); const encryptedShareBuffer = Buffer.from(encryptedShare, "utf-8"); diff --git a/backend/tss_api/src/api/presign_ed25519/index.ts b/backend/tss_api/src/api/presign_ed25519/index.ts deleted file mode 100644 index 71c649019..000000000 --- a/backend/tss_api/src/api/presign_ed25519/index.ts +++ /dev/null @@ -1,116 +0,0 @@ -import { - createTssSession, - createTssStage, -} from "@oko-wallet/oko-pg-interface/tss"; -import type { - PresignEd25519Request, - PresignEd25519Response, - PresignEd25519StageData, -} from "@oko-wallet/oko-types/tss"; -import { - TssStageType, - PresignEd25519StageStatus, -} from "@oko-wallet/oko-types/tss"; -import type { KeygenEd25519Output } from "@oko-wallet/oko-types/tss"; -import type { OkoApiResponse } from "@oko-wallet/oko-types/api_response"; -import { Pool } from "pg"; -import { decryptDataAsync } from "@oko-wallet/crypto-js/node"; -import { runSignRound1Ed25519 } from "@oko-wallet/teddsa-addon/src/server"; - -import { validateWalletEmail } from "@oko-wallet-tss-api/api/utils"; - -export async function runPresignEd25519( - db: Pool, - encryptionSecret: string, - request: PresignEd25519Request, -): Promise> { - try { - const { email, wallet_id, customer_id } = request; - - const validateWalletEmailRes = await validateWalletEmail( - db, - wallet_id, - email, - ); - if (validateWalletEmailRes.success === false) { - return { - success: false, - code: "UNAUTHORIZED", - msg: validateWalletEmailRes.err, - }; - } - const wallet = validateWalletEmailRes.data; - - if (wallet.curve_type !== "ed25519") { - return { - success: false, - code: "INVALID_WALLET_TYPE", - msg: `Wallet is not ed25519 type: ${wallet.curve_type}`, - }; - } - - const encryptedShare = wallet.enc_tss_share.toString("utf-8"); - const decryptedShare = await decryptDataAsync( - encryptedShare, - encryptionSecret, - ); - const keygenOutput: KeygenEd25519Output = JSON.parse(decryptedShare); - - // Generate nonces and commitments (Round 1 without message) - const round1Result = runSignRound1Ed25519( - new Uint8Array(keygenOutput.key_package), - ); - - // Create TSS session - const sessionRes = await createTssSession(db, { - customer_id, - wallet_id, - }); - if (!sessionRes.success) { - return { - success: false, - code: "UNKNOWN_ERROR", - msg: `Failed to create TSS session: ${sessionRes.err}`, - }; - } - const session = sessionRes.data; - - // Create TSS stage with presign data (nonces stored for later use) - const stageData: PresignEd25519StageData = { - nonces: round1Result.nonces, - identifier: round1Result.identifier, - commitments: round1Result.commitments, - }; - - const stageRes = await createTssStage(db, { - session_id: session.session_id, - stage_type: TssStageType.PRESIGN_ED25519, - stage_status: PresignEd25519StageStatus.COMPLETED, - stage_data: stageData, - }); - if (!stageRes.success) { - return { - success: false, - code: "UNKNOWN_ERROR", - msg: `Failed to create TSS stage: ${stageRes.err}`, - }; - } - - return { - success: true, - data: { - session_id: session.session_id, - commitments_0: { - identifier: round1Result.identifier, - commitments: round1Result.commitments, - }, - }, - }; - } catch (error) { - return { - success: false, - code: "UNKNOWN_ERROR", - msg: `runPresignEd25519 error: ${error instanceof Error ? error.message : String(error)}`, - }; - } -} diff --git a/backend/tss_api/src/api/sign_ed25519/index.test.ts b/backend/tss_api/src/api/sign_ed25519/index.test.ts index 3ea8ebd46..0f16d68cd 100644 --- a/backend/tss_api/src/api/sign_ed25519/index.test.ts +++ b/backend/tss_api/src/api/sign_ed25519/index.test.ts @@ -1,711 +1,868 @@ -// TODO: refactor this tests @chemonoworld - -// import { jest } from "@jest/globals"; -// import { Pool } from "pg"; -// import type { -// SignEd25519Round1Request, -// SignEd25519Round2Request, -// SignEd25519AggregateRequest, -// } from "@oko-wallet/oko-types/tss"; -// import type { TeddsaKeygenOutput } from "@oko-wallet/teddsa-interface"; -// import { Participant } from "@oko-wallet/teddsa-interface"; -// import { -// runKeygenCentralizedEd25519, -// runSignRound1Ed25519 as clientRunSignRound1Ed25519, -// runSignRound2Ed25519 as clientRunSignRound2Ed25519, -// runAggregateEd25519 as clientRunAggregateEd25519, -// runVerifyEd25519, -// } from "@oko-wallet/teddsa-addon/src/server"; -// import { createPgConn } from "@oko-wallet/postgres-lib"; -// import type { WalletStatus } from "@oko-wallet/oko-types/wallets"; -// import { insertKSNode } from "@oko-wallet/oko-pg-interface/ks_nodes"; -// import { createWallet } from "@oko-wallet/oko-pg-interface/oko_wallets"; -// import { createUser } from "@oko-wallet/oko-pg-interface/oko_users"; -// import { insertKeyShareNodeMeta } from "@oko-wallet/oko-pg-interface/key_share_node_meta"; -// import { insertCustomer } from "@oko-wallet/oko-pg-interface/customers"; -// import { encryptDataAsync } from "@oko-wallet/crypto-js/node"; - -// import { resetPgDatabase } from "@oko-wallet-tss-api/testing/database"; -// import { testPgConfig } from "@oko-wallet-tss-api/database/test_config"; -// import { -// runSignEd25519Round1, -// runSignEd25519Round2, -// runSignEd25519Aggregate, -// } from "@oko-wallet-tss-api/api/sign_ed25519"; -// import { TEMP_ENC_SECRET } from "@oko-wallet-tss-api/api/utils"; - -// const SSS_THRESHOLD = 2; -// const TEST_EMAIL = "test-ed25519@test.com"; - -// interface TestSetupResult { -// pool: Pool; -// walletId: string; -// customerId: string; -// clientKeygenOutput: TeddsaKeygenOutput; -// serverKeygenOutput: TeddsaKeygenOutput; -// } - -// async function setUpKSNodes(pool: Pool): Promise { -// const ksNodeNames = ["ksNode1", "ksNode2"]; -// const ksNodeIds = []; -// const createKSNodesRes = await Promise.all( -// ksNodeNames.map((ksNodeName) => -// insertKSNode(pool, ksNodeName, `http://test.com/${ksNodeName}`), -// ), -// ); -// for (const res of createKSNodesRes) { -// if (res.success === false) { -// throw new Error("Failed to create ks nodes"); -// } -// ksNodeIds.push(res.data.node_id); -// } -// return ksNodeIds; -// } - -// async function setUpEd25519Wallet(pool: Pool): Promise { -// // Generate keys using centralized keygen -// const keygenResult = runKeygenCentralizedEd25519(); -// const clientKeygenOutput = keygenResult.keygen_outputs[Participant.P0]; -// const serverKeygenOutput = keygenResult.keygen_outputs[Participant.P1]; - -// // Set up KS nodes and metadata -// const ksNodeIds = await setUpKSNodes(pool); -// await insertKeyShareNodeMeta(pool, { -// sss_threshold: SSS_THRESHOLD, -// }); - -// // Create customer -// const customerId = crypto.randomUUID(); -// const insertCustomerRes = await insertCustomer(pool, { -// customer_id: customerId, -// label: "test-customer", -// status: "ACTIVE", -// url: null, -// logo_url: null, -// theme: "dark", -// }); -// if (insertCustomerRes.success === false) { -// throw new Error(`Failed to create customer: ${insertCustomerRes.err}`); -// } - -// // Create user -// const createUserRes = await createUser(pool, TEST_EMAIL, "google"); -// if (createUserRes.success === false) { -// throw new Error(`Failed to create user: ${createUserRes.err}`); -// } -// const userId = createUserRes.data.user_id; - -// // Encrypt server key package -// const serverKeyPackageJson = JSON.stringify(serverKeygenOutput); -// const encryptedShare = await encryptDataAsync( -// serverKeyPackageJson, -// TEMP_ENC_SECRET, -// ); - -// // Create Ed25519 wallet -// const createWalletRes = await createWallet(pool, { -// user_id: userId, -// curve_type: "ed25519", -// public_key: Buffer.from(keygenResult.public_key), -// enc_tss_share: Buffer.from(encryptedShare, "utf-8"), -// sss_threshold: SSS_THRESHOLD, -// status: "ACTIVE" as WalletStatus, -// }); -// if (createWalletRes.success === false) { -// throw new Error(`Failed to create wallet: ${createWalletRes.err}`); -// } -// const walletId = createWalletRes.data.wallet_id; - -// return { -// pool, -// walletId, -// customerId, -// clientKeygenOutput, -// serverKeygenOutput, -// }; -// } - -// describe("Ed25519 Signing", () => { -// let pool: Pool; - -// beforeAll(async () => { -// const config = testPgConfig; -// const createPostgresRes = await createPgConn({ -// database: config.database, -// host: config.host, -// password: config.password, -// user: config.user, -// port: config.port, -// ssl: config.ssl, -// }); - -// if (createPostgresRes.success === false) { -// console.error(createPostgresRes.err); -// throw new Error("Failed to create postgres database"); -// } - -// pool = createPostgresRes.data; -// }); - -// afterAll(async () => { -// await pool.end(); -// }); - -// beforeEach(async () => { -// await resetPgDatabase(pool); -// }); - -// describe("runSignEd25519Round1", () => { -// it("should generate commitments successfully", async () => { -// const { walletId, customerId } = await setUpEd25519Wallet(pool); -// const testMessage = new TextEncoder().encode("Test message"); - -// const request: SignEd25519Round1Request = { -// email: TEST_EMAIL, -// wallet_id: walletId, -// customer_id: customerId, -// msg: [...testMessage], -// }; - -// const result = await runSignEd25519Round1(pool, TEMP_ENC_SECRET, request); - -// expect(result.success).toBe(true); -// if (result.success) { -// expect(result.data.session_id).toBeDefined(); -// expect(result.data.commitments_0).toBeDefined(); -// expect(result.data.commitments_0.identifier).toBeDefined(); -// expect(result.data.commitments_0.commitments).toBeDefined(); -// expect(Array.isArray(result.data.commitments_0.identifier)).toBe(true); -// expect(Array.isArray(result.data.commitments_0.commitments)).toBe(true); -// } -// }); - -// it("should fail with invalid email", async () => { -// const { walletId, customerId } = await setUpEd25519Wallet(pool); -// const testMessage = new TextEncoder().encode("Test message"); - -// const request: SignEd25519Round1Request = { -// email: "wrong@test.com", -// wallet_id: walletId, -// customer_id: customerId, -// msg: [...testMessage], -// }; - -// const result = await runSignEd25519Round1(pool, TEMP_ENC_SECRET, request); - -// expect(result.success).toBe(false); -// if (!result.success) { -// expect(result.code).toBe("UNAUTHORIZED"); -// } -// }); - -// it("should fail with invalid wallet_id", async () => { -// const { customerId } = await setUpEd25519Wallet(pool); -// const testMessage = new TextEncoder().encode("Test message"); - -// const request: SignEd25519Round1Request = { -// email: TEST_EMAIL, -// wallet_id: "00000000-0000-0000-0000-000000000000", -// customer_id: customerId, -// msg: [...testMessage], -// }; - -// const result = await runSignEd25519Round1(pool, TEMP_ENC_SECRET, request); - -// expect(result.success).toBe(false); -// if (!result.success) { -// expect(result.code).toBe("UNAUTHORIZED"); -// } -// }); -// }); - -// describe("runSignEd25519Round2", () => { -// it("should generate signature share successfully", async () => { -// const { walletId, customerId, clientKeygenOutput } = -// await setUpEd25519Wallet(pool); -// const testMessage = new TextEncoder().encode("Test message for Ed25519"); - -// // Round 1: Get server commitments -// const round1Request: SignEd25519Round1Request = { -// email: TEST_EMAIL, -// wallet_id: walletId, -// customer_id: customerId, -// msg: [...testMessage], -// }; -// const round1Result = await runSignEd25519Round1( -// pool, -// TEMP_ENC_SECRET, -// round1Request, -// ); -// expect(round1Result.success).toBe(true); -// if (!round1Result.success) throw new Error("Round 1 failed"); - -// // Client generates their round 1 output -// const clientRound1 = clientRunSignRound1Ed25519( -// new Uint8Array(clientKeygenOutput.key_package), -// ); - -// // Round 2: Get server signature share -// const round2Request: SignEd25519Round2Request = { -// email: TEST_EMAIL, -// wallet_id: walletId, -// session_id: round1Result.data.session_id, -// commitments_1: { -// identifier: clientRound1.identifier, -// commitments: clientRound1.commitments, -// }, -// }; -// const round2Result = await runSignEd25519Round2( -// pool, -// TEMP_ENC_SECRET, -// round2Request, -// ); - -// expect(round2Result.success).toBe(true); -// if (round2Result.success) { -// expect(round2Result.data.signature_share_0).toBeDefined(); -// expect(round2Result.data.signature_share_0.identifier).toBeDefined(); -// expect( -// round2Result.data.signature_share_0.signature_share, -// ).toBeDefined(); -// } -// }); - -// it("should fail with invalid session_id", async () => { -// const { walletId, customerId, clientKeygenOutput } = -// await setUpEd25519Wallet(pool); -// const testMessage = new TextEncoder().encode("Test message"); - -// const clientRound1 = clientRunSignRound1Ed25519( -// new Uint8Array(clientKeygenOutput.key_package), -// ); - -// const round2Request: SignEd25519Round2Request = { -// email: TEST_EMAIL, -// wallet_id: walletId, -// session_id: "00000000-0000-0000-0000-000000000000", -// commitments_1: { -// identifier: clientRound1.identifier, -// commitments: clientRound1.commitments, -// }, -// }; -// const result = await runSignEd25519Round2( -// pool, -// TEMP_ENC_SECRET, -// round2Request, -// ); - -// expect(result.success).toBe(false); -// if (!result.success) { -// expect(result.code).toBe("INVALID_TSS_SESSION"); -// } -// }); - -// it("should fail when Round2 is called twice (duplicate call prevention)", async () => { -// const { walletId, customerId, clientKeygenOutput } = -// await setUpEd25519Wallet(pool); -// const testMessage = new TextEncoder().encode("Test message"); - -// // Round 1: Get server commitments -// const round1Request: SignEd25519Round1Request = { -// email: TEST_EMAIL, -// wallet_id: walletId, -// customer_id: customerId, -// msg: [...testMessage], -// }; -// const round1Result = await runSignEd25519Round1( -// pool, -// TEMP_ENC_SECRET, -// round1Request, -// ); -// expect(round1Result.success).toBe(true); -// if (!round1Result.success) throw new Error("Round 1 failed"); - -// const clientRound1 = clientRunSignRound1Ed25519( -// new Uint8Array(clientKeygenOutput.key_package), -// ); - -// // First Round 2 call - should succeed -// const round2Request: SignEd25519Round2Request = { -// email: TEST_EMAIL, -// wallet_id: walletId, -// session_id: round1Result.data.session_id, -// commitments_1: { -// identifier: clientRound1.identifier, -// commitments: clientRound1.commitments, -// }, -// }; -// const round2Result = await runSignEd25519Round2( -// pool, -// TEMP_ENC_SECRET, -// round2Request, -// ); -// expect(round2Result.success).toBe(true); - -// // Second Round 2 call with same session - should fail -// const duplicateRound2Result = await runSignEd25519Round2( -// pool, -// TEMP_ENC_SECRET, -// round2Request, -// ); - -// expect(duplicateRound2Result.success).toBe(false); -// if (!duplicateRound2Result.success) { -// expect(duplicateRound2Result.code).toBe("INVALID_TSS_SESSION"); -// } -// }); - -// it("should fail when using COMPLETED session for Round2", async () => { -// const { walletId, customerId, clientKeygenOutput } = -// await setUpEd25519Wallet(pool); -// const testMessage = new TextEncoder().encode("Test message for signing"); - -// // Complete full signing flow first -// const round1Res = await runSignEd25519Round1(pool, TEMP_ENC_SECRET, { -// email: TEST_EMAIL, -// wallet_id: walletId, -// customer_id: customerId, -// msg: [...testMessage], -// }); -// expect(round1Res.success).toBe(true); -// if (!round1Res.success) throw new Error("Round 1 failed"); - -// const clientR1 = clientRunSignRound1Ed25519( -// new Uint8Array(clientKeygenOutput.key_package), -// ); - -// const allCommitments = [ -// { identifier: clientR1.identifier, commitments: clientR1.commitments }, -// { -// identifier: round1Res.data.commitments_0.identifier, -// commitments: round1Res.data.commitments_0.commitments, -// }, -// ].sort((a, b) => (a.identifier[0] ?? 0) - (b.identifier[0] ?? 0)); - -// const round2Res = await runSignEd25519Round2(pool, TEMP_ENC_SECRET, { -// email: TEST_EMAIL, -// wallet_id: walletId, -// session_id: round1Res.data.session_id, -// commitments_1: { -// identifier: clientR1.identifier, -// commitments: clientR1.commitments, -// }, -// }); -// expect(round2Res.success).toBe(true); -// if (!round2Res.success) throw new Error("Round 2 failed"); - -// const clientR2 = clientRunSignRound2Ed25519( -// testMessage, -// new Uint8Array(clientKeygenOutput.key_package), -// new Uint8Array(clientR1.nonces), -// allCommitments, -// ); - -// const allShares = [ -// { -// identifier: clientR2.identifier, -// signature_share: clientR2.signature_share, -// }, -// { -// identifier: round2Res.data.signature_share_0.identifier, -// signature_share: round2Res.data.signature_share_0.signature_share, -// }, -// ].sort((a, b) => (a.identifier[0] ?? 0) - (b.identifier[0] ?? 0)); - -// // Complete the signing with Aggregate -// const aggRes = await runSignEd25519Aggregate(pool, TEMP_ENC_SECRET, { -// email: TEST_EMAIL, -// wallet_id: walletId, -// msg: [...testMessage], -// all_commitments: allCommitments, -// all_signature_shares: allShares, -// }); -// expect(aggRes.success).toBe(true); - -// // Now try to use the COMPLETED session for Round2 - should fail -// const newClientR1 = clientRunSignRound1Ed25519( -// new Uint8Array(clientKeygenOutput.key_package), -// ); -// const replayRound2Res = await runSignEd25519Round2( -// pool, -// TEMP_ENC_SECRET, -// { -// email: TEST_EMAIL, -// wallet_id: walletId, -// session_id: round1Res.data.session_id, // Reusing completed session -// commitments_1: { -// identifier: newClientR1.identifier, -// commitments: newClientR1.commitments, -// }, -// }, -// ); - -// expect(replayRound2Res.success).toBe(false); -// if (!replayRound2Res.success) { -// expect(replayRound2Res.code).toBe("INVALID_TSS_SESSION"); -// } -// }); -// }); - -// describe("runSignEd25519Aggregate", () => { -// it("should aggregate signatures and produce valid signature", async () => { -// const { walletId, customerId, clientKeygenOutput, serverKeygenOutput } = -// await setUpEd25519Wallet(pool); -// const testMessage = new TextEncoder().encode("Test message for signing"); - -// // Round 1: Both parties generate commitments -// const round1Request: SignEd25519Round1Request = { -// email: TEST_EMAIL, -// wallet_id: walletId, -// customer_id: customerId, -// msg: [...testMessage], -// }; -// const serverRound1Result = await runSignEd25519Round1( -// pool, -// TEMP_ENC_SECRET, -// round1Request, -// ); -// expect(serverRound1Result.success).toBe(true); -// if (!serverRound1Result.success) throw new Error("Server Round 1 failed"); - -// const clientRound1 = clientRunSignRound1Ed25519( -// new Uint8Array(clientKeygenOutput.key_package), -// ); - -// // Collect all commitments (sorted by identifier) -// const allCommitments = [ -// { -// identifier: clientRound1.identifier, -// commitments: clientRound1.commitments, -// }, -// { -// identifier: serverRound1Result.data.commitments_0.identifier, -// commitments: serverRound1Result.data.commitments_0.commitments, -// }, -// ].sort((a, b) => (a.identifier[0] ?? 0) - (b.identifier[0] ?? 0)); - -// // Round 2: Both parties generate signature shares -// const round2Request: SignEd25519Round2Request = { -// email: TEST_EMAIL, -// wallet_id: walletId, -// session_id: serverRound1Result.data.session_id, -// commitments_1: { -// identifier: clientRound1.identifier, -// commitments: clientRound1.commitments, -// }, -// }; -// const serverRound2Result = await runSignEd25519Round2( -// pool, -// TEMP_ENC_SECRET, -// round2Request, -// ); -// expect(serverRound2Result.success).toBe(true); -// if (!serverRound2Result.success) throw new Error("Server Round 2 failed"); - -// const clientRound2 = clientRunSignRound2Ed25519( -// testMessage, -// new Uint8Array(clientKeygenOutput.key_package), -// new Uint8Array(clientRound1.nonces), -// allCommitments, -// ); - -// // Collect all signature shares (sorted by identifier) -// const allSignatureShares = [ -// { -// identifier: clientRound2.identifier, -// signature_share: clientRound2.signature_share, -// }, -// { -// identifier: serverRound2Result.data.signature_share_0.identifier, -// signature_share: -// serverRound2Result.data.signature_share_0.signature_share, -// }, -// ].sort((a, b) => (a.identifier[0] ?? 0) - (b.identifier[0] ?? 0)); - -// // Aggregate -// const aggregateRequest: SignEd25519AggregateRequest = { -// email: TEST_EMAIL, -// wallet_id: walletId, -// msg: [...testMessage], -// all_commitments: allCommitments, -// all_signature_shares: allSignatureShares, -// }; -// const aggregateResult = await runSignEd25519Aggregate( -// pool, -// TEMP_ENC_SECRET, -// aggregateRequest, -// ); - -// expect(aggregateResult.success).toBe(true); -// if (aggregateResult.success) { -// expect(aggregateResult.data.signature).toBeDefined(); -// expect(aggregateResult.data.signature.length).toBe(64); - -// // Verify the signature -// const isValid = runVerifyEd25519( -// testMessage, -// new Uint8Array(aggregateResult.data.signature), -// new Uint8Array(clientKeygenOutput.public_key_package), -// ); -// expect(isValid).toBe(true); -// } -// }); - -// it("should fail with wrong wallet type", async () => { -// // Create a secp256k1 wallet instead of ed25519 -// await setUpKSNodes(pool); -// await insertKeyShareNodeMeta(pool, { sss_threshold: SSS_THRESHOLD }); - -// const createUserRes = await createUser(pool, TEST_EMAIL, "google"); -// if (!createUserRes.success) throw new Error("Failed to create user"); - -// const encryptedShare = await encryptDataAsync( -// JSON.stringify({ private_share: "test", public_key: "test" }), -// TEMP_ENC_SECRET, -// ); - -// const createWalletRes = await createWallet(pool, { -// user_id: createUserRes.data.user_id, -// curve_type: "secp256k1", -// public_key: Buffer.from("03" + "00".repeat(32), "hex"), -// enc_tss_share: Buffer.from(encryptedShare, "utf-8"), -// sss_threshold: SSS_THRESHOLD, -// status: "ACTIVE" as WalletStatus, -// }); -// if (!createWalletRes.success) throw new Error("Failed to create wallet"); - -// const aggregateRequest: SignEd25519AggregateRequest = { -// email: TEST_EMAIL, -// wallet_id: createWalletRes.data.wallet_id, -// msg: [1, 2, 3], -// all_commitments: [], -// all_signature_shares: [], -// }; - -// const result = await runSignEd25519Aggregate( -// pool, -// TEMP_ENC_SECRET, -// aggregateRequest, -// ); - -// expect(result.success).toBe(false); -// if (!result.success) { -// expect(result.code).toBe("INVALID_WALLET_TYPE"); -// } -// }); - -// it("should fail with invalid wallet_id", async () => { -// await setUpEd25519Wallet(pool); - -// const aggregateRequest: SignEd25519AggregateRequest = { -// email: TEST_EMAIL, -// wallet_id: "00000000-0000-0000-0000-000000000000", -// msg: [1, 2, 3], -// all_commitments: [], -// all_signature_shares: [], -// }; - -// const result = await runSignEd25519Aggregate( -// pool, -// TEMP_ENC_SECRET, -// aggregateRequest, -// ); - -// expect(result.success).toBe(false); -// if (!result.success) { -// expect(result.code).toBe("UNAUTHORIZED"); -// } -// }); -// }); - -// describe("Full signing flow", () => { -// it("should complete full signing flow with valid signature verification", async () => { -// const { walletId, customerId, clientKeygenOutput } = -// await setUpEd25519Wallet(pool); -// const messages = [ -// "Hello, Solana!", -// "Transaction data", -// "Another message to sign", -// ]; - -// for (const msgStr of messages) { -// const message = new TextEncoder().encode(msgStr); - -// // Round 1 -// const round1Res = await runSignEd25519Round1(pool, TEMP_ENC_SECRET, { -// email: TEST_EMAIL, -// wallet_id: walletId, -// customer_id: customerId, -// msg: [...message], -// }); -// expect(round1Res.success).toBe(true); -// if (!round1Res.success) continue; - -// const clientR1 = clientRunSignRound1Ed25519( -// new Uint8Array(clientKeygenOutput.key_package), -// ); - -// const allCommitments = [ -// { -// identifier: clientR1.identifier, -// commitments: clientR1.commitments, -// }, -// { -// identifier: round1Res.data.commitments_0.identifier, -// commitments: round1Res.data.commitments_0.commitments, -// }, -// ].sort((a, b) => (a.identifier[0] ?? 0) - (b.identifier[0] ?? 0)); - -// // Round 2 -// const round2Res = await runSignEd25519Round2(pool, TEMP_ENC_SECRET, { -// email: TEST_EMAIL, -// wallet_id: walletId, -// session_id: round1Res.data.session_id, -// commitments_1: { -// identifier: clientR1.identifier, -// commitments: clientR1.commitments, -// }, -// }); -// expect(round2Res.success).toBe(true); -// if (!round2Res.success) continue; - -// const clientR2 = clientRunSignRound2Ed25519( -// message, -// new Uint8Array(clientKeygenOutput.key_package), -// new Uint8Array(clientR1.nonces), -// allCommitments, -// ); - -// const allShares = [ -// { -// identifier: clientR2.identifier, -// signature_share: clientR2.signature_share, -// }, -// { -// identifier: round2Res.data.signature_share_0.identifier, -// signature_share: round2Res.data.signature_share_0.signature_share, -// }, -// ].sort((a, b) => (a.identifier[0] ?? 0) - (b.identifier[0] ?? 0)); - -// // Aggregate -// const aggRes = await runSignEd25519Aggregate(pool, TEMP_ENC_SECRET, { -// email: TEST_EMAIL, -// wallet_id: walletId, -// msg: [...message], -// all_commitments: allCommitments, -// all_signature_shares: allShares, -// }); -// expect(aggRes.success).toBe(true); -// if (!aggRes.success) continue; - -// // Verify -// const isValid = runVerifyEd25519( -// message, -// new Uint8Array(aggRes.data.signature), -// new Uint8Array(clientKeygenOutput.public_key_package), -// ); -// expect(isValid).toBe(true); -// } -// }); -// }); -// }); +import { Pool } from "pg"; +import type { + SignEd25519Round1Request, + SignEd25519Round2Request, + SignEd25519AggregateRequest, +} from "@oko-wallet/oko-types/tss"; +import { + TssStageType, + SignEd25519StageStatus, + TssSessionState, +} from "@oko-wallet/oko-types/tss"; +import { getTssStageWithSessionData } from "@oko-wallet/oko-pg-interface/tss"; +import { Participant } from "@oko-wallet/teddsa-interface"; +import { + runKeygenCentralizedEd25519, + runSignRound1Ed25519 as clientRunSignRound1Ed25519, + runSignRound2Ed25519 as clientRunSignRound2Ed25519, + runVerifyEd25519, + extractKeyPackageSharesEd25519, +} from "@oko-wallet/teddsa-addon/src/server"; +import { createPgConn } from "@oko-wallet/postgres-lib"; +import type { WalletStatus } from "@oko-wallet/oko-types/wallets"; +import { insertKSNode } from "@oko-wallet/oko-pg-interface/ks_nodes"; +import { createWallet } from "@oko-wallet/oko-pg-interface/oko_wallets"; +import { createUser } from "@oko-wallet/oko-pg-interface/oko_users"; +import { insertKeyShareNodeMeta } from "@oko-wallet/oko-pg-interface/key_share_node_meta"; +import { insertCustomer } from "@oko-wallet/oko-pg-interface/customers"; +import { encryptDataAsync } from "@oko-wallet/crypto-js/node"; + +import { resetPgDatabase } from "@oko-wallet-tss-api/testing/database"; +import { testPgConfig } from "@oko-wallet-tss-api/database/test_config"; +import { + runSignEd25519Round1, + runSignEd25519Round2, + runSignEd25519Aggregate, +} from "@oko-wallet-tss-api/api/sign_ed25519"; +import { TEMP_ENC_SECRET } from "@oko-wallet-tss-api/api/utils"; + +const SSS_THRESHOLD = 2; +const TEST_EMAIL = "test-ed25519@test.com"; + +interface TestSetupResult { + pool: Pool; + walletId: string; + customerId: string; + clientKeygenOutput: ReturnType< + typeof runKeygenCentralizedEd25519 + >["keygen_outputs"][Participant.P0]; + serverKeygenOutput: ReturnType< + typeof runKeygenCentralizedEd25519 + >["keygen_outputs"][Participant.P1]; +} + +async function setUpKSNodes(pool: Pool): Promise { + const ksNodeNames = ["ksNode1", "ksNode2"]; + const ksNodeIds = []; + const createKSNodesRes = await Promise.all( + ksNodeNames.map((ksNodeName) => + insertKSNode(pool, ksNodeName, `http://test.com/${ksNodeName}`), + ), + ); + for (const res of createKSNodesRes) { + if (res.success === false) { + throw new Error("Failed to create ks nodes"); + } + ksNodeIds.push(res.data.node_id); + } + return ksNodeIds; +} + +async function setUpEd25519Wallet(pool: Pool): Promise { + // Generate keys using centralized keygen + const keygenResult = runKeygenCentralizedEd25519(); + const clientKeygenOutput = keygenResult.keygen_outputs[Participant.P0]; + const serverKeygenOutput = keygenResult.keygen_outputs[Participant.P1]; + + // Set up KS nodes and metadata + const ksNodeIds = await setUpKSNodes(pool); + await insertKeyShareNodeMeta(pool, { + sss_threshold: SSS_THRESHOLD, + }); + + // Create customer + const customerId = crypto.randomUUID(); + const insertCustomerRes = await insertCustomer(pool, { + customer_id: customerId, + label: "test-customer", + status: "ACTIVE", + url: null, + logo_url: null, + theme: "dark", + }); + if (insertCustomerRes.success === false) { + throw new Error(`Failed to create customer: ${insertCustomerRes.err}`); + } + + // Create user + const createUserRes = await createUser(pool, TEST_EMAIL, "google"); + if (createUserRes.success === false) { + throw new Error(`Failed to create user: ${createUserRes.err}`); + } + const userId = createUserRes.data.user_id; + + // Extract signing_share and verifying_share from server key_package + const serverKeyPackageShares = extractKeyPackageSharesEd25519( + new Uint8Array(serverKeygenOutput.key_package), + ); + + // Store only signing_share and verifying_share (64 bytes total) + const sharesData = { + signing_share: serverKeyPackageShares.signing_share, + verifying_share: serverKeyPackageShares.verifying_share, + }; + + const encryptedShare = await encryptDataAsync( + JSON.stringify(sharesData), + TEMP_ENC_SECRET, + ); + + // Create Ed25519 wallet + const createWalletRes = await createWallet(pool, { + user_id: userId, + curve_type: "ed25519", + public_key: Buffer.from(keygenResult.public_key), + enc_tss_share: Buffer.from(encryptedShare, "utf-8"), + sss_threshold: SSS_THRESHOLD, + status: "ACTIVE" as WalletStatus, + }); + if (createWalletRes.success === false) { + throw new Error(`Failed to create wallet: ${createWalletRes.err}`); + } + const walletId = createWalletRes.data.wallet_id; + + return { + pool, + walletId, + customerId, + clientKeygenOutput, + serverKeygenOutput, + }; +} + +describe("Ed25519 Signing", () => { + let pool: Pool; + + beforeAll(async () => { + const config = testPgConfig; + const createPostgresRes = await createPgConn({ + database: config.database, + host: config.host, + password: config.password, + user: config.user, + port: config.port, + ssl: config.ssl, + }); + + if (createPostgresRes.success === false) { + console.error(createPostgresRes.err); + throw new Error("Failed to create postgres database"); + } + + pool = createPostgresRes.data; + }); + + afterAll(async () => { + await pool.end(); + }); + + beforeEach(async () => { + await resetPgDatabase(pool); + }); + + describe("runSignEd25519Round1", () => { + it("should generate commitments successfully", async () => { + const { walletId, customerId } = await setUpEd25519Wallet(pool); + const testMessage = new TextEncoder().encode("Test message"); + + const request: SignEd25519Round1Request = { + email: TEST_EMAIL, + wallet_id: walletId, + customer_id: customerId, + msg: [...testMessage], + }; + + const result = await runSignEd25519Round1(pool, TEMP_ENC_SECRET, request); + + expect(result.success).toBe(true); + if (result.success) { + expect(result.data.session_id).toBeDefined(); + expect(result.data.commitments_0).toBeDefined(); + expect(result.data.commitments_0.identifier).toBeDefined(); + expect(result.data.commitments_0.commitments).toBeDefined(); + expect(Array.isArray(result.data.commitments_0.identifier)).toBe(true); + expect(Array.isArray(result.data.commitments_0.commitments)).toBe(true); + + // Verify stage status is ROUND_1 + const getStageRes = await getTssStageWithSessionData( + pool, + result.data.session_id, + TssStageType.SIGN_ED25519, + ); + expect(getStageRes.success).toBe(true); + if (getStageRes.success && getStageRes.data) { + expect(getStageRes.data.stage_status).toBe( + SignEd25519StageStatus.ROUND_1, + ); + expect(getStageRes.data.session_state).toBe( + TssSessionState.IN_PROGRESS, + ); + } + } + }); + + it("should fail with invalid email", async () => { + const { walletId, customerId } = await setUpEd25519Wallet(pool); + const testMessage = new TextEncoder().encode("Test message"); + + const request: SignEd25519Round1Request = { + email: "wrong@test.com", + wallet_id: walletId, + customer_id: customerId, + msg: [...testMessage], + }; + + const result = await runSignEd25519Round1(pool, TEMP_ENC_SECRET, request); + + expect(result.success).toBe(false); + if (!result.success) { + expect(result.code).toBe("UNAUTHORIZED"); + } + }); + + it("should fail with invalid wallet_id", async () => { + const { customerId } = await setUpEd25519Wallet(pool); + const testMessage = new TextEncoder().encode("Test message"); + + const request: SignEd25519Round1Request = { + email: TEST_EMAIL, + wallet_id: "00000000-0000-0000-0000-000000000000", + customer_id: customerId, + msg: [...testMessage], + }; + + const result = await runSignEd25519Round1(pool, TEMP_ENC_SECRET, request); + + expect(result.success).toBe(false); + if (!result.success) { + expect(result.code).toBe("UNAUTHORIZED"); + } + }); + }); + + describe("runSignEd25519Round2", () => { + it("should generate signature share successfully", async () => { + const { walletId, customerId, clientKeygenOutput } = + await setUpEd25519Wallet(pool); + const testMessage = new TextEncoder().encode("Test message for Ed25519"); + + // Round 1: Get server commitments + const round1Request: SignEd25519Round1Request = { + email: TEST_EMAIL, + wallet_id: walletId, + customer_id: customerId, + msg: [...testMessage], + }; + const round1Result = await runSignEd25519Round1( + pool, + TEMP_ENC_SECRET, + round1Request, + ); + expect(round1Result.success).toBe(true); + if (!round1Result.success) throw new Error("Round 1 failed"); + + // Client generates their round 1 output + const clientRound1 = clientRunSignRound1Ed25519( + new Uint8Array(clientKeygenOutput.key_package), + ); + + // Round 2: Get server signature share + const round2Request: SignEd25519Round2Request = { + email: TEST_EMAIL, + wallet_id: walletId, + session_id: round1Result.data.session_id, + commitments_1: { + identifier: clientRound1.identifier, + commitments: clientRound1.commitments, + }, + }; + const round2Result = await runSignEd25519Round2( + pool, + TEMP_ENC_SECRET, + round2Request, + ); + + expect(round2Result.success).toBe(true); + if (round2Result.success) { + expect(round2Result.data.signature_share_0).toBeDefined(); + expect(round2Result.data.signature_share_0.identifier).toBeDefined(); + expect( + round2Result.data.signature_share_0.signature_share, + ).toBeDefined(); + + // Verify stage status is ROUND_2 (not COMPLETED) + const getStageRes = await getTssStageWithSessionData( + pool, + round1Result.data.session_id, + TssStageType.SIGN_ED25519, + ); + expect(getStageRes.success).toBe(true); + if (getStageRes.success && getStageRes.data) { + expect(getStageRes.data.stage_status).toBe( + SignEd25519StageStatus.ROUND_2, + ); + expect(getStageRes.data.session_state).toBe( + TssSessionState.IN_PROGRESS, + ); + } + } + }); + + it("should fail with invalid session_id", async () => { + const { walletId, customerId, clientKeygenOutput } = + await setUpEd25519Wallet(pool); + const testMessage = new TextEncoder().encode("Test message"); + + const clientRound1 = clientRunSignRound1Ed25519( + new Uint8Array(clientKeygenOutput.key_package), + ); + + const round2Request: SignEd25519Round2Request = { + email: TEST_EMAIL, + wallet_id: walletId, + session_id: "00000000-0000-0000-0000-000000000000", + commitments_1: { + identifier: clientRound1.identifier, + commitments: clientRound1.commitments, + }, + }; + const result = await runSignEd25519Round2( + pool, + TEMP_ENC_SECRET, + round2Request, + ); + + expect(result.success).toBe(false); + if (!result.success) { + expect(result.code).toBe("INVALID_TSS_SESSION"); + } + }); + + it("should fail when Round2 is called twice (duplicate call prevention)", async () => { + const { walletId, customerId, clientKeygenOutput } = + await setUpEd25519Wallet(pool); + const testMessage = new TextEncoder().encode("Test message"); + + // Round 1: Get server commitments + const round1Request: SignEd25519Round1Request = { + email: TEST_EMAIL, + wallet_id: walletId, + customer_id: customerId, + msg: [...testMessage], + }; + const round1Result = await runSignEd25519Round1( + pool, + TEMP_ENC_SECRET, + round1Request, + ); + expect(round1Result.success).toBe(true); + if (!round1Result.success) throw new Error("Round 1 failed"); + + const clientRound1 = clientRunSignRound1Ed25519( + new Uint8Array(clientKeygenOutput.key_package), + ); + + // First Round 2 call - should succeed + const round2Request: SignEd25519Round2Request = { + email: TEST_EMAIL, + wallet_id: walletId, + session_id: round1Result.data.session_id, + commitments_1: { + identifier: clientRound1.identifier, + commitments: clientRound1.commitments, + }, + }; + const round2Result = await runSignEd25519Round2( + pool, + TEMP_ENC_SECRET, + round2Request, + ); + expect(round2Result.success).toBe(true); + + // Verify stage status is ROUND_2 after first Round2 call + const getStageRes = await getTssStageWithSessionData( + pool, + round1Result.data.session_id, + TssStageType.SIGN_ED25519, + ); + expect(getStageRes.success).toBe(true); + if (getStageRes.success && getStageRes.data) { + expect(getStageRes.data.stage_status).toBe( + SignEd25519StageStatus.ROUND_2, + ); + } + + // Second Round 2 call with same session - should fail (already ROUND_2) + const duplicateRound2Result = await runSignEd25519Round2( + pool, + TEMP_ENC_SECRET, + round2Request, + ); + + expect(duplicateRound2Result.success).toBe(false); + if (!duplicateRound2Result.success) { + expect(duplicateRound2Result.code).toBe("INVALID_TSS_SESSION"); + } + }); + + it("should fail when using COMPLETED session for Round2", async () => { + const { walletId, customerId, clientKeygenOutput } = + await setUpEd25519Wallet(pool); + const testMessage = new TextEncoder().encode("Test message for signing"); + + // Complete full signing flow first + const round1Res = await runSignEd25519Round1(pool, TEMP_ENC_SECRET, { + email: TEST_EMAIL, + wallet_id: walletId, + customer_id: customerId, + msg: [...testMessage], + }); + expect(round1Res.success).toBe(true); + if (!round1Res.success) throw new Error("Round 1 failed"); + + const clientR1 = clientRunSignRound1Ed25519( + new Uint8Array(clientKeygenOutput.key_package), + ); + + const allCommitments = [ + { identifier: clientR1.identifier, commitments: clientR1.commitments }, + { + identifier: round1Res.data.commitments_0.identifier, + commitments: round1Res.data.commitments_0.commitments, + }, + ].sort((a, b) => (a.identifier[0] ?? 0) - (b.identifier[0] ?? 0)); + + const round2Res = await runSignEd25519Round2(pool, TEMP_ENC_SECRET, { + email: TEST_EMAIL, + wallet_id: walletId, + session_id: round1Res.data.session_id, + commitments_1: { + identifier: clientR1.identifier, + commitments: clientR1.commitments, + }, + }); + expect(round2Res.success).toBe(true); + if (!round2Res.success) throw new Error("Round 2 failed"); + + const clientR2 = clientRunSignRound2Ed25519( + testMessage, + new Uint8Array(clientKeygenOutput.key_package), + new Uint8Array(clientR1.nonces), + allCommitments, + ); + + const allShares = [ + { + identifier: clientR2.identifier, + signature_share: clientR2.signature_share, + }, + { + identifier: round2Res.data.signature_share_0.identifier, + signature_share: round2Res.data.signature_share_0.signature_share, + }, + ].sort((a, b) => (a.identifier[0] ?? 0) - (b.identifier[0] ?? 0)); + + // Extract user's verifying_share for aggregate + const userKeyPackageShares = extractKeyPackageSharesEd25519( + new Uint8Array(clientKeygenOutput.key_package), + ); + + // Verify stage status is ROUND_2 before aggregate + const getStageBeforeAggRes = await getTssStageWithSessionData( + pool, + round1Res.data.session_id, + TssStageType.SIGN_ED25519, + ); + expect(getStageBeforeAggRes.success).toBe(true); + if (getStageBeforeAggRes.success && getStageBeforeAggRes.data) { + expect(getStageBeforeAggRes.data.stage_status).toBe( + SignEd25519StageStatus.ROUND_2, + ); + } + + // Complete the signing with Aggregate + const aggRes = await runSignEd25519Aggregate(pool, TEMP_ENC_SECRET, { + email: TEST_EMAIL, + wallet_id: walletId, + session_id: round1Res.data.session_id, + msg: [...testMessage], + all_commitments: allCommitments, + all_signature_shares: allShares, + user_verifying_share: userKeyPackageShares.verifying_share, + }); + expect(aggRes.success).toBe(true); + + // Verify stage status is COMPLETED after aggregate + const getStageAfterAggRes = await getTssStageWithSessionData( + pool, + round1Res.data.session_id, + TssStageType.SIGN_ED25519, + ); + expect(getStageAfterAggRes.success).toBe(true); + if (getStageAfterAggRes.success && getStageAfterAggRes.data) { + expect(getStageAfterAggRes.data.stage_status).toBe( + SignEd25519StageStatus.COMPLETED, + ); + expect(getStageAfterAggRes.data.session_state).toBe( + TssSessionState.COMPLETED, + ); + } + + // Now try to use the COMPLETED session for Round2 - should fail + const newClientR1 = clientRunSignRound1Ed25519( + new Uint8Array(clientKeygenOutput.key_package), + ); + const replayRound2Res = await runSignEd25519Round2( + pool, + TEMP_ENC_SECRET, + { + email: TEST_EMAIL, + wallet_id: walletId, + session_id: round1Res.data.session_id, // Reusing completed session + commitments_1: { + identifier: newClientR1.identifier, + commitments: newClientR1.commitments, + }, + }, + ); + + expect(replayRound2Res.success).toBe(false); + if (!replayRound2Res.success) { + expect(replayRound2Res.code).toBe("INVALID_TSS_SESSION"); + } + }); + }); + + describe("runSignEd25519Aggregate", () => { + it("should aggregate signatures and produce valid signature", async () => { + const { walletId, customerId, clientKeygenOutput, serverKeygenOutput } = + await setUpEd25519Wallet(pool); + const testMessage = new TextEncoder().encode("Test message for signing"); + + // Round 1: Both parties generate commitments + const round1Request: SignEd25519Round1Request = { + email: TEST_EMAIL, + wallet_id: walletId, + customer_id: customerId, + msg: [...testMessage], + }; + const serverRound1Result = await runSignEd25519Round1( + pool, + TEMP_ENC_SECRET, + round1Request, + ); + expect(serverRound1Result.success).toBe(true); + if (!serverRound1Result.success) throw new Error("Server Round 1 failed"); + + const clientRound1 = clientRunSignRound1Ed25519( + new Uint8Array(clientKeygenOutput.key_package), + ); + + // Collect all commitments (sorted by identifier) + const allCommitments = [ + { + identifier: clientRound1.identifier, + commitments: clientRound1.commitments, + }, + { + identifier: serverRound1Result.data.commitments_0.identifier, + commitments: serverRound1Result.data.commitments_0.commitments, + }, + ].sort((a, b) => (a.identifier[0] ?? 0) - (b.identifier[0] ?? 0)); + + // Round 2: Both parties generate signature shares + const round2Request: SignEd25519Round2Request = { + email: TEST_EMAIL, + wallet_id: walletId, + session_id: serverRound1Result.data.session_id, + commitments_1: { + identifier: clientRound1.identifier, + commitments: clientRound1.commitments, + }, + }; + const serverRound2Result = await runSignEd25519Round2( + pool, + TEMP_ENC_SECRET, + round2Request, + ); + expect(serverRound2Result.success).toBe(true); + if (!serverRound2Result.success) throw new Error("Server Round 2 failed"); + + const clientRound2 = clientRunSignRound2Ed25519( + testMessage, + new Uint8Array(clientKeygenOutput.key_package), + new Uint8Array(clientRound1.nonces), + allCommitments, + ); + + // Collect all signature shares (sorted by identifier) + const allSignatureShares = [ + { + identifier: clientRound2.identifier, + signature_share: clientRound2.signature_share, + }, + { + identifier: serverRound2Result.data.signature_share_0.identifier, + signature_share: + serverRound2Result.data.signature_share_0.signature_share, + }, + ].sort((a, b) => (a.identifier[0] ?? 0) - (b.identifier[0] ?? 0)); + + // Extract user's verifying_share for aggregate + const userKeyPackageShares = extractKeyPackageSharesEd25519( + new Uint8Array(clientKeygenOutput.key_package), + ); + + // Aggregate + const aggregateRequest: SignEd25519AggregateRequest = { + email: TEST_EMAIL, + wallet_id: walletId, + session_id: serverRound1Result.data.session_id, + msg: [...testMessage], + all_commitments: allCommitments, + all_signature_shares: allSignatureShares, + user_verifying_share: userKeyPackageShares.verifying_share, + }; + const aggregateResult = await runSignEd25519Aggregate( + pool, + TEMP_ENC_SECRET, + aggregateRequest, + ); + + expect(aggregateResult.success).toBe(true); + if (aggregateResult.success) { + expect(aggregateResult.data.signature).toBeDefined(); + expect(aggregateResult.data.signature.length).toBe(64); + + // Verify stage status is COMPLETED after aggregate + const getStageRes = await getTssStageWithSessionData( + pool, + serverRound1Result.data.session_id, + TssStageType.SIGN_ED25519, + ); + expect(getStageRes.success).toBe(true); + if (getStageRes.success && getStageRes.data) { + expect(getStageRes.data.stage_status).toBe( + SignEd25519StageStatus.COMPLETED, + ); + expect(getStageRes.data.session_state).toBe( + TssSessionState.COMPLETED, + ); + } + + // Verify the signature + const isValid = runVerifyEd25519( + testMessage, + new Uint8Array(aggregateResult.data.signature), + new Uint8Array(clientKeygenOutput.public_key_package), + ); + expect(isValid).toBe(true); + } + }); + + it("should fail with wrong wallet type", async () => { + // Create a secp256k1 wallet instead of ed25519 + await setUpKSNodes(pool); + await insertKeyShareNodeMeta(pool, { sss_threshold: SSS_THRESHOLD }); + + const createUserRes = await createUser(pool, TEST_EMAIL, "google"); + if (!createUserRes.success) throw new Error("Failed to create user"); + + const encryptedShare = await encryptDataAsync( + JSON.stringify({ private_share: "test", public_key: "test" }), + TEMP_ENC_SECRET, + ); + + const createWalletRes = await createWallet(pool, { + user_id: createUserRes.data.user_id, + curve_type: "secp256k1", + public_key: Buffer.from("03" + "00".repeat(32), "hex"), + enc_tss_share: Buffer.from(encryptedShare, "utf-8"), + sss_threshold: SSS_THRESHOLD, + status: "ACTIVE" as WalletStatus, + }); + if (!createWalletRes.success) throw new Error("Failed to create wallet"); + + const aggregateRequest: SignEd25519AggregateRequest = { + email: TEST_EMAIL, + wallet_id: createWalletRes.data.wallet_id, + session_id: "00000000-0000-0000-0000-000000000000", // Dummy session_id for error test + msg: [1, 2, 3], + all_commitments: [], + all_signature_shares: [], + user_verifying_share: new Array(32).fill(0), // Dummy value for error test + }; + + const result = await runSignEd25519Aggregate( + pool, + TEMP_ENC_SECRET, + aggregateRequest, + ); + + expect(result.success).toBe(false); + if (!result.success) { + expect(result.code).toBe("INVALID_WALLET_TYPE"); + } + }); + + it("should fail with invalid wallet_id", async () => { + await setUpEd25519Wallet(pool); + + const aggregateRequest: SignEd25519AggregateRequest = { + email: TEST_EMAIL, + wallet_id: "00000000-0000-0000-0000-000000000000", + session_id: "00000000-0000-0000-0000-000000000000", // Dummy session_id for error test + msg: [1, 2, 3], + all_commitments: [], + all_signature_shares: [], + user_verifying_share: new Array(32).fill(0), // Dummy value for error test + }; + + const result = await runSignEd25519Aggregate( + pool, + TEMP_ENC_SECRET, + aggregateRequest, + ); + + expect(result.success).toBe(false); + if (!result.success) { + expect(result.code).toBe("UNAUTHORIZED"); + } + }); + }); + + describe("Full signing flow", () => { + it("should complete full signing flow with valid signature verification", async () => { + const { walletId, customerId, clientKeygenOutput } = + await setUpEd25519Wallet(pool); + const messages = [ + "Hello, Solana!", + "Transaction data", + "Another message to sign", + ]; + + for (const msgStr of messages) { + const message = new TextEncoder().encode(msgStr); + + // Round 1 + const round1Res = await runSignEd25519Round1(pool, TEMP_ENC_SECRET, { + email: TEST_EMAIL, + wallet_id: walletId, + customer_id: customerId, + msg: [...message], + }); + expect(round1Res.success).toBe(true); + if (!round1Res.success) continue; + + const clientR1 = clientRunSignRound1Ed25519( + new Uint8Array(clientKeygenOutput.key_package), + ); + + const allCommitments = [ + { + identifier: clientR1.identifier, + commitments: clientR1.commitments, + }, + { + identifier: round1Res.data.commitments_0.identifier, + commitments: round1Res.data.commitments_0.commitments, + }, + ].sort((a, b) => (a.identifier[0] ?? 0) - (b.identifier[0] ?? 0)); + + // Round 2 + const round2Res = await runSignEd25519Round2(pool, TEMP_ENC_SECRET, { + email: TEST_EMAIL, + wallet_id: walletId, + session_id: round1Res.data.session_id, + commitments_1: { + identifier: clientR1.identifier, + commitments: clientR1.commitments, + }, + }); + expect(round2Res.success).toBe(true); + if (!round2Res.success) continue; + + const clientR2 = clientRunSignRound2Ed25519( + message, + new Uint8Array(clientKeygenOutput.key_package), + new Uint8Array(clientR1.nonces), + allCommitments, + ); + + const allShares = [ + { + identifier: clientR2.identifier, + signature_share: clientR2.signature_share, + }, + { + identifier: round2Res.data.signature_share_0.identifier, + signature_share: round2Res.data.signature_share_0.signature_share, + }, + ].sort((a, b) => (a.identifier[0] ?? 0) - (b.identifier[0] ?? 0)); + + // Extract user's verifying_share for aggregate + const userKeyPackageShares = extractKeyPackageSharesEd25519( + new Uint8Array(clientKeygenOutput.key_package), + ); + + // Verify stage status is ROUND_2 before aggregate + const getStageBeforeAggRes = await getTssStageWithSessionData( + pool, + round1Res.data.session_id, + TssStageType.SIGN_ED25519, + ); + if (getStageBeforeAggRes.success && getStageBeforeAggRes.data) { + expect(getStageBeforeAggRes.data.stage_status).toBe( + SignEd25519StageStatus.ROUND_2, + ); + } + + // Aggregate + const aggRes = await runSignEd25519Aggregate(pool, TEMP_ENC_SECRET, { + email: TEST_EMAIL, + wallet_id: walletId, + session_id: round1Res.data.session_id, + msg: [...message], + all_commitments: allCommitments, + all_signature_shares: allShares, + user_verifying_share: userKeyPackageShares.verifying_share, + }); + expect(aggRes.success).toBe(true); + if (!aggRes.success) continue; + + // Verify stage status is COMPLETED after aggregate + const getStageAfterAggRes = await getTssStageWithSessionData( + pool, + round1Res.data.session_id, + TssStageType.SIGN_ED25519, + ); + if (getStageAfterAggRes.success && getStageAfterAggRes.data) { + expect(getStageAfterAggRes.data.stage_status).toBe( + SignEd25519StageStatus.COMPLETED, + ); + expect(getStageAfterAggRes.data.session_state).toBe( + TssSessionState.COMPLETED, + ); + } + + // Verify + const isValid = runVerifyEd25519( + message, + new Uint8Array(aggRes.data.signature), + new Uint8Array(clientKeygenOutput.public_key_package), + ); + expect(isValid).toBe(true); + } + }); + }); +}); diff --git a/backend/tss_api/src/api/sign_ed25519/index.ts b/backend/tss_api/src/api/sign_ed25519/index.ts index 38c9eed68..2e33a2704 100644 --- a/backend/tss_api/src/api/sign_ed25519/index.ts +++ b/backend/tss_api/src/api/sign_ed25519/index.ts @@ -11,17 +11,12 @@ import type { SignEd25519AggregateRequest, SignEd25519AggregateResponse, SignEd25519StageData, - SignEd25519Request, - SignEd25519Response, - PresignEd25519StageData, } from "@oko-wallet/oko-types/tss"; import { TssStageType, SignEd25519StageStatus, - PresignEd25519StageStatus, TssSessionState, } from "@oko-wallet/oko-types/tss"; -import type { KeygenEd25519Output } from "@oko-wallet/oko-types/tss"; import type { OkoApiResponse } from "@oko-wallet/oko-types/api_response"; import { Pool } from "pg"; import { decryptDataAsync } from "@oko-wallet/crypto-js/node"; @@ -29,7 +24,13 @@ import { runSignRound1Ed25519, runSignRound2Ed25519, runAggregateEd25519, + reconstructKeyPackageEd25519, + reconstructPublicKeyPackageEd25519, } from "@oko-wallet/teddsa-addon/src/server"; +import { + Participant, + participantToIdentifier, +} from "@oko-wallet/teddsa-interface"; import { validateWalletEmail, @@ -73,11 +74,34 @@ export async function runSignEd25519Round1( encryptedShare, encryptionSecret, ); - const keygenOutput: KeygenEd25519Output = JSON.parse(decryptedShare); + const storedShares = JSON.parse(decryptedShare) as { + signing_share: number[]; + verifying_share: number[]; + }; - const round1Result = runSignRound1Ed25519( - new Uint8Array(keygenOutput.key_package), - ); + // Reconstruct key_package from stored shares + const serverIdentifier = participantToIdentifier(Participant.P1); + const verifyingKey = Array.from(wallet.public_key); + const minSigners = 2; + + let keyPackageBytes: Uint8Array; + try { + keyPackageBytes = reconstructKeyPackageEd25519( + new Uint8Array(storedShares.signing_share), + new Uint8Array(storedShares.verifying_share), + new Uint8Array(serverIdentifier), + new Uint8Array(verifyingKey), + minSigners, + ); + } catch (error) { + return { + success: false, + code: "UNKNOWN_ERROR", + msg: `Failed to reconstruct key_package: ${error instanceof Error ? error.message : String(error)}`, + }; + } + + const round1Result = runSignRound1Ed25519(keyPackageBytes); // Create TSS session const sessionRes = await createTssSession(db, { @@ -219,7 +243,32 @@ export async function runSignEd25519Round2( encryptedShare, encryptionSecret, ); - const keygenOutput: KeygenEd25519Output = JSON.parse(decryptedShare); + const storedShares = JSON.parse(decryptedShare) as { + signing_share: number[]; + verifying_share: number[]; + }; + + // Reconstruct key_package from stored shares + const serverIdentifier = participantToIdentifier(Participant.P1); + const verifyingKey = Array.from(wallet.public_key); + const minSigners = 2; + + let keyPackageBytes: Uint8Array; + try { + keyPackageBytes = reconstructKeyPackageEd25519( + new Uint8Array(storedShares.signing_share), + new Uint8Array(storedShares.verifying_share), + new Uint8Array(serverIdentifier), + new Uint8Array(verifyingKey), + minSigners, + ); + } catch (error) { + return { + success: false, + code: "UNKNOWN_ERROR", + msg: `Failed to reconstruct key_package: ${error instanceof Error ? error.message : String(error)}`, + }; + } const serverCommitment = { identifier, @@ -235,24 +284,23 @@ export async function runSignEd25519Round2( const round2Result = runSignRound2Ed25519( new Uint8Array(msg), - new Uint8Array(keygenOutput.key_package), + keyPackageBytes, new Uint8Array(nonces), allCommitments, ); - // Update stage and session atomically const updateRes = await updateTssStageWithSessionState( db, stage.stage_id, session_id, { - stage_status: SignEd25519StageStatus.COMPLETED, + stage_status: SignEd25519StageStatus.ROUND_2, stage_data: { ...stageData, signature_share: round2Result.signature_share, }, }, - TssSessionState.COMPLETED, + TssSessionState.IN_PROGRESS, ); if (!updateRes.success) { return { @@ -280,14 +328,21 @@ export async function runSignEd25519Round2( } } -// New presign-based sign function -export async function runSignEd25519( +export async function runSignEd25519Aggregate( db: Pool, encryptionSecret: string, - request: SignEd25519Request, -): Promise> { + request: SignEd25519AggregateRequest, +): Promise> { try { - const { email, wallet_id, session_id, msg, commitments_1 } = request; + const { + email, + wallet_id, + session_id, + msg, + all_commitments, + all_signature_shares, + user_verifying_share, + } = request; const validateWalletEmailRes = await validateWalletEmail( db, @@ -311,11 +366,44 @@ export async function runSignEd25519( }; } - // Get presign stage with session data + // Decrypt stored shares + const encryptedShare = wallet.enc_tss_share.toString("utf-8"); + const decryptedShare = await decryptDataAsync( + encryptedShare, + encryptionSecret, + ); + const storedShares = JSON.parse(decryptedShare) as { + signing_share: number[]; + verifying_share: number[]; + }; + + // Reconstruct public_key_package from user and server verifying_shares + const userIdentifier = participantToIdentifier(Participant.P0); + const serverIdentifier = participantToIdentifier(Participant.P1); + const verifyingKey = Array.from(wallet.public_key); + + let publicKeyPackageBytes: Uint8Array; + try { + publicKeyPackageBytes = reconstructPublicKeyPackageEd25519( + new Uint8Array(user_verifying_share), + new Uint8Array(userIdentifier), + new Uint8Array(storedShares.verifying_share), + new Uint8Array(serverIdentifier), + new Uint8Array(verifyingKey), + ); + } catch (error) { + return { + success: false, + code: "UNKNOWN_ERROR", + msg: `Failed to reconstruct public_key_package: ${error instanceof Error ? error.message : String(error)}`, + }; + } + + // Get stage with session data to update status after aggregate const getStageRes = await getTssStageWithSessionData( db, session_id, - TssStageType.PRESIGN_ED25519, + TssStageType.SIGN_ED25519, ); if (getStageRes.success === false) { return { @@ -335,60 +423,35 @@ export async function runSignEd25519( }; } - // Validate stage status (must be COMPLETED presign, not USED) - if (!validateTssStage(stage, PresignEd25519StageStatus.COMPLETED)) { + // Validate stage status (should be ROUND_2) + if (!validateTssStage(stage, SignEd25519StageStatus.ROUND_2)) { return { success: false, code: "INVALID_TSS_SESSION", - msg: "Presign not found or already used. Please call presign_ed25519 first.", + msg: "Round 2 state not found. Please call round2 first.", }; } - const stageData = stage.stage_data as PresignEd25519StageData; - const { nonces, identifier, commitments } = stageData; - - if (!nonces || !identifier || !commitments) { - return { - success: false, - code: "INVALID_TSS_SESSION", - msg: "Missing presign data in stage", - }; - } - - const encryptedShare = wallet.enc_tss_share.toString("utf-8"); - const decryptedShare = await decryptDataAsync( - encryptedShare, - encryptionSecret, - ); - const keygenOutput: KeygenEd25519Output = JSON.parse(decryptedShare); - - const serverCommitment = { - identifier, - commitments, - }; - - const allCommitments = [serverCommitment, commitments_1]; - allCommitments.sort((a, b) => { - const idA = a.identifier[0] ?? 0; - const idB = b.identifier[0] ?? 0; - return idA - idB; - }); - - const round2Result = runSignRound2Ed25519( + // Aggregate signature + const aggregateResult = runAggregateEd25519( new Uint8Array(msg), - new Uint8Array(keygenOutput.key_package), - new Uint8Array(nonces), - allCommitments, + all_commitments, + all_signature_shares, + publicKeyPackageBytes, ); - // Mark presign as USED and complete the session + // Update stage and session to COMPLETED after successful aggregate + const stageData = stage.stage_data as SignEd25519StageData; const updateRes = await updateTssStageWithSessionState( db, stage.stage_id, session_id, { - stage_status: PresignEd25519StageStatus.USED, - stage_data: stageData, + stage_status: SignEd25519StageStatus.COMPLETED, + stage_data: { + ...stageData, + signature: aggregateResult.signature, + }, }, TssSessionState.COMPLETED, ); @@ -400,69 +463,6 @@ export async function runSignEd25519( }; } - return { - success: true, - data: { - signature_share_0: { - identifier: round2Result.identifier, - signature_share: round2Result.signature_share, - }, - }, - }; - } catch (error) { - return { - success: false, - code: "UNKNOWN_ERROR", - msg: `runSignEd25519 error: ${error instanceof Error ? error.message : String(error)}`, - }; - } -} - -export async function runSignEd25519Aggregate( - db: Pool, - encryptionSecret: string, - request: SignEd25519AggregateRequest, -): Promise> { - try { - const { email, wallet_id, msg, all_commitments, all_signature_shares } = - request; - - const validateWalletEmailRes = await validateWalletEmail( - db, - wallet_id, - email, - ); - if (validateWalletEmailRes.success === false) { - return { - success: false, - code: "UNAUTHORIZED", - msg: validateWalletEmailRes.err, - }; - } - const wallet = validateWalletEmailRes.data; - - if (wallet.curve_type !== "ed25519") { - return { - success: false, - code: "INVALID_WALLET_TYPE", - msg: `Wallet is not ed25519 type: ${wallet.curve_type}`, - }; - } - - const encryptedShare = wallet.enc_tss_share.toString("utf-8"); - const decryptedShare = await decryptDataAsync( - encryptedShare, - encryptionSecret, - ); - const keygenOutput: KeygenEd25519Output = JSON.parse(decryptedShare); - - const aggregateResult = runAggregateEd25519( - new Uint8Array(msg), - all_commitments, - all_signature_shares, - new Uint8Array(keygenOutput.public_key_package), - ); - return { success: true, data: { diff --git a/backend/tss_api/src/api/wallet_ed25519/index.ts b/backend/tss_api/src/api/wallet_ed25519/index.ts index 107c2a360..30a21876e 100644 --- a/backend/tss_api/src/api/wallet_ed25519/index.ts +++ b/backend/tss_api/src/api/wallet_ed25519/index.ts @@ -8,10 +8,12 @@ import { Participant, participantToIdentifier, } from "@oko-wallet/teddsa-interface"; +import { reconstructPublicKeyPackageEd25519 } from "@oko-wallet/teddsa-addon/src/server"; export interface WalletEd25519PublicInfoRequest { user_identifier: string; auth_type: AuthType; + user_verifying_share: number[]; // P0's verifying_share (32 bytes) } export interface WalletEd25519PublicInfoResponse { @@ -31,7 +33,7 @@ export async function getWalletEd25519PublicInfo( request: WalletEd25519PublicInfoRequest, ): Promise> { try { - const { user_identifier, auth_type } = request; + const { user_identifier, auth_type, user_verifying_share } = request; // Get user const getUserRes = await getUserByEmailAndAuthType( @@ -77,25 +79,44 @@ export async function getWalletEd25519PublicInfo( } const wallet = getWalletRes.data; - // Decrypt the stored key package data + // Decrypt stored shares const encryptedShare = wallet.enc_tss_share.toString("utf-8"); const decryptedShare = await decryptDataAsync( encryptedShare, encryptionSecret, ); - const keyPackageData = JSON.parse(decryptedShare) as { - key_package: number[]; - public_key_package: number[]; - identifier: number[]; + const storedShares = JSON.parse(decryptedShare) as { + signing_share: number[]; + verifying_share: number[]; }; - // Return public info for client key recovery - // Server stores keygen_2 (P1), but client needs identifier for P0 + // Reconstruct public_key_package from user and server verifying_shares + const userIdentifier = participantToIdentifier(Participant.P0); + const serverIdentifier = participantToIdentifier(Participant.P1); + const verifyingKey = Array.from(wallet.public_key); + + let publicKeyPackageBytes: Uint8Array; + try { + publicKeyPackageBytes = reconstructPublicKeyPackageEd25519( + new Uint8Array(user_verifying_share), + new Uint8Array(userIdentifier), + new Uint8Array(storedShares.verifying_share), + new Uint8Array(serverIdentifier), + new Uint8Array(verifyingKey), + ); + } catch (error) { + return { + success: false, + code: "UNKNOWN_ERROR", + msg: `Failed to reconstruct public_key_package: ${error instanceof Error ? error.message : String(error)}`, + }; + } + return { success: true, data: { public_key: wallet.public_key.toString("hex"), - public_key_package: keyPackageData.public_key_package, + public_key_package: Array.from(publicKeyPackageBytes), identifier: participantToIdentifier(Participant.P0), }, }; diff --git a/backend/tss_api/src/routes/index.ts b/backend/tss_api/src/routes/index.ts index 183639b6a..4894fa75d 100644 --- a/backend/tss_api/src/routes/index.ts +++ b/backend/tss_api/src/routes/index.ts @@ -4,7 +4,6 @@ import { setKeygenRoutes } from "./keygen"; import { setKeygenEd25519Routes } from "./keygen_ed25519"; import { setTriplesRoutes } from "./triples"; import { setPresignRoutes } from "./presign"; -import { setPresignEd25519Routes } from "./presign_ed25519"; import { setSignRoutes } from "./sign"; import { setSignEd25519Routes } from "./sign_ed25519"; import { setWalletEd25519Routes } from "./wallet_ed25519"; @@ -19,7 +18,6 @@ export function makeTssRouter() { setKeygenEd25519Routes(router); setTriplesRoutes(router); setPresignRoutes(router); - setPresignEd25519Routes(router); setSignRoutes(router); setSignEd25519Routes(router); setWalletEd25519Routes(router); diff --git a/backend/tss_api/src/routes/presign_ed25519.ts b/backend/tss_api/src/routes/presign_ed25519.ts deleted file mode 100644 index 08efca0a0..000000000 --- a/backend/tss_api/src/routes/presign_ed25519.ts +++ /dev/null @@ -1,129 +0,0 @@ -import type { Response, Router } from "express"; -import type { - PresignEd25519Body, - PresignEd25519Response, -} from "@oko-wallet/oko-types/tss"; -import type { OkoApiResponse } from "@oko-wallet/oko-types/api_response"; -import { ErrorCodeMap } from "@oko-wallet/oko-api-error-codes"; -import { - ErrorResponseSchema, - UserAuthHeaderSchema, -} from "@oko-wallet/oko-api-openapi/common"; -import { registry } from "@oko-wallet/oko-api-openapi"; - -import { runPresignEd25519 } from "@oko-wallet-tss-api/api/presign_ed25519"; -import { - type UserAuthenticatedRequest, - userJwtMiddleware, - sendResponseWithNewToken, -} from "@oko-wallet-tss-api/middleware/keplr_auth"; -import { apiKeyMiddleware } from "@oko-wallet-tss-api/middleware/api_key_auth"; -import { tssActivateMiddleware } from "@oko-wallet-tss-api/middleware/tss_activate"; - -export function setPresignEd25519Routes(router: Router) { - registry.registerPath({ - method: "post", - path: "/tss/v1/presign_ed25519", - tags: ["TSS"], - summary: "Generate Ed25519 presign (nonces and commitments)", - description: - "Pre-generate nonces and commitments for Ed25519 threshold signing. " + - "This can be called before knowing the message to sign.", - security: [{ userAuth: [] }], - request: { - headers: UserAuthHeaderSchema, - body: { - required: false, - content: { - "application/json": { - schema: { - type: "object", - properties: {}, - }, - }, - }, - }, - }, - responses: { - 200: { - description: "Successfully generated presign", - content: { - "application/json": { - schema: { - type: "object", - properties: { - success: { type: "boolean" }, - data: { - type: "object", - properties: { - session_id: { type: "string" }, - commitments_0: { - type: "object", - properties: { - identifier: { - type: "array", - items: { type: "number" }, - }, - commitments: { - type: "array", - items: { type: "number" }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - 401: { - description: "Unauthorized", - content: { "application/json": { schema: ErrorResponseSchema } }, - }, - 500: { - description: "Internal server error", - content: { "application/json": { schema: ErrorResponseSchema } }, - }, - }, - }); - - router.post( - "/presign_ed25519", - [apiKeyMiddleware, userJwtMiddleware, tssActivateMiddleware], - async ( - req: UserAuthenticatedRequest, - res: Response>, - ) => { - const state = req.app.locals as any; - const user = res.locals.user; - const apiKey = res.locals.api_key; - - if (!user.wallet_id_ed25519) { - res.status(400).json({ - success: false, - code: "WALLET_NOT_FOUND", - msg: "Ed25519 wallet not found. Please create one first.", - }); - return; - } - - const result = await runPresignEd25519( - state.db, - state.encryption_secret, - { - email: user.email.toLowerCase(), - wallet_id: user.wallet_id_ed25519, - customer_id: apiKey.customer_id, - }, - ); - - if (result.success === false) { - res.status(ErrorCodeMap[result.code] ?? 500).json(result); - return; - } - - sendResponseWithNewToken(res, result.data); - }, - ); -} diff --git a/backend/tss_api/src/routes/sign_ed25519.ts b/backend/tss_api/src/routes/sign_ed25519.ts index 54374cf57..8986a47d2 100644 --- a/backend/tss_api/src/routes/sign_ed25519.ts +++ b/backend/tss_api/src/routes/sign_ed25519.ts @@ -6,8 +6,6 @@ import type { SignEd25519Round2Response, SignEd25519AggregateBody, SignEd25519AggregateResponse, - SignEd25519Body, - SignEd25519Response, } from "@oko-wallet/oko-types/tss"; import type { OkoApiResponse } from "@oko-wallet/oko-types/api_response"; import { ErrorCodeMap } from "@oko-wallet/oko-api-error-codes"; @@ -21,7 +19,6 @@ import { runSignEd25519Round1, runSignEd25519Round2, runSignEd25519Aggregate, - runSignEd25519, } from "@oko-wallet-tss-api/api/sign_ed25519"; import { type UserAuthenticatedRequest, @@ -315,43 +312,6 @@ export function setSignEd25519Routes(router: Router) { }, }); - router.post( - "/sign_ed25519", - [userJwtMiddleware, tssActivateMiddleware], - async ( - req: UserAuthenticatedRequest, - res: Response>, - ) => { - const state = req.app.locals as any; - const user = res.locals.user; - const body = req.body; - - if (!user.wallet_id_ed25519) { - res.status(400).json({ - success: false, - code: "WALLET_NOT_FOUND", - msg: "Ed25519 wallet not found. Please create one first.", - }); - return; - } - - const result = await runSignEd25519(state.db, state.encryption_secret, { - email: user.email.toLowerCase(), - wallet_id: user.wallet_id_ed25519, - session_id: body.session_id, - msg: body.msg, - commitments_1: body.commitments_1, - }); - - if (result.success === false) { - res.status(ErrorCodeMap[result.code] ?? 500).json(result); - return; - } - - sendResponseWithNewToken(res, result.data); - }, - ); - registry.registerPath({ method: "post", path: "/tss/v1/sign_ed25519/aggregate", @@ -368,6 +328,7 @@ export function setSignEd25519Routes(router: Router) { schema: { type: "object", properties: { + session_id: { type: "string", format: "uuid" }, msg: { type: "array", items: { type: "number" } }, all_commitments: { type: "array", @@ -392,8 +353,19 @@ export function setSignEd25519Routes(router: Router) { }, }, }, + user_verifying_share: { + type: "array", + items: { type: "number" }, + description: "P0's verifying_share (32 bytes)", + }, }, - required: ["msg", "all_commitments", "all_signature_shares"], + required: [ + "session_id", + "msg", + "all_commitments", + "all_signature_shares", + "user_verifying_share", + ], }, }, }, @@ -447,9 +419,11 @@ export function setSignEd25519Routes(router: Router) { { email: user.email.toLowerCase(), wallet_id: user.wallet_id, + session_id: body.session_id, msg: body.msg, all_commitments: body.all_commitments, all_signature_shares: body.all_signature_shares, + user_verifying_share: body.user_verifying_share, }, ); diff --git a/backend/tss_api/src/routes/wallet_ed25519.ts b/backend/tss_api/src/routes/wallet_ed25519.ts index a32ad738c..3ee93bd34 100644 --- a/backend/tss_api/src/routes/wallet_ed25519.ts +++ b/backend/tss_api/src/routes/wallet_ed25519.ts @@ -30,6 +30,24 @@ export function setWalletEd25519Routes(router: Router) { security: [{ oauthAuth: [] }], request: { headers: OAuthHeaderSchema, + body: { + required: true, + content: { + "application/json": { + schema: { + type: "object", + properties: { + user_verifying_share: { + type: "array", + items: { type: "number" }, + description: "P0's verifying_share (32 bytes)", + }, + }, + required: ["user_verifying_share"], + }, + }, + }, + }, }, responses: { 200: { @@ -76,7 +94,7 @@ export function setWalletEd25519Routes(router: Router) { oauthMiddleware, tssActivateMiddleware, async ( - req: OAuthAuthenticatedRequest>, + req: OAuthAuthenticatedRequest<{ user_verifying_share: number[] }>, res: Response< OkoApiResponse, OAuthLocals @@ -84,6 +102,7 @@ export function setWalletEd25519Routes(router: Router) { ) => { const state = req.app.locals; const oauthUser = res.locals.oauth_user; + const body = req.body; const user_identifier = oauthUser?.user_identifier; if (!user_identifier) { @@ -101,6 +120,7 @@ export function setWalletEd25519Routes(router: Router) { { user_identifier, auth_type: oauthUser.type, + user_verifying_share: body.user_verifying_share, }, ); diff --git a/common/oko_types/src/tss/sign_ed25519.ts b/common/oko_types/src/tss/sign_ed25519.ts index 4a28f1445..221e04a52 100644 --- a/common/oko_types/src/tss/sign_ed25519.ts +++ b/common/oko_types/src/tss/sign_ed25519.ts @@ -38,9 +38,11 @@ export type SignEd25519Round2Body = { export interface SignEd25519AggregateRequest { email: string; wallet_id: string; + session_id: string; msg: number[]; all_commitments: CommitmentEntry[]; all_signature_shares: SignatureShareEntry[]; + user_verifying_share: number[]; // P0's verifying_share (32 bytes) } export interface SignEd25519AggregateResponse { @@ -48,43 +50,14 @@ export interface SignEd25519AggregateResponse { } export type SignEd25519AggregateBody = { + session_id: string; msg: number[]; all_commitments: CommitmentEntry[]; all_signature_shares: SignatureShareEntry[]; + user_verifying_share: number[]; }; export interface SignEd25519ServerState { nonces: number[]; identifier: number[]; } - -export interface PresignEd25519Request { - email: string; - wallet_id: string; - customer_id: string; -} - -export interface PresignEd25519Response { - session_id: string; - commitments_0: CommitmentEntry; -} - -export type PresignEd25519Body = Record; - -export interface SignEd25519Request { - email: string; - wallet_id: string; - session_id: string; - msg: number[]; - commitments_1: CommitmentEntry; -} - -export interface SignEd25519Response { - signature_share_0: SignatureShareEntry; -} - -export type SignEd25519Body = { - session_id: string; - msg: number[]; - commitments_1: CommitmentEntry; -}; diff --git a/common/oko_types/src/tss/tss_stage.ts b/common/oko_types/src/tss/tss_stage.ts index 65d129caa..7af8688ef 100644 --- a/common/oko_types/src/tss/tss_stage.ts +++ b/common/oko_types/src/tss/tss_stage.ts @@ -18,7 +18,6 @@ export enum TssStageType { PRESIGN = "PRESIGN", SIGN = "SIGN", SIGN_ED25519 = "SIGN_ED25519", - PRESIGN_ED25519 = "PRESIGN_ED25519", } interface TssStageBase { @@ -132,12 +131,6 @@ export type SignEd25519Stage = TssStageBase & { stage_data: SignEd25519StageData; }; -export type PresignEd25519Stage = TssStageBase & { - stage_type: TssStageType.PRESIGN_ED25519; - stage_status: PresignEd25519StageStatus; - stage_data: PresignEd25519StageData; -}; - export type TssStageStatus = | TriplesStageStatus | PresignStageStatus @@ -149,8 +142,7 @@ export type TssStage = | TriplesStage | PresignStage | SignStage - | SignEd25519Stage - | PresignEd25519Stage; + | SignEd25519Stage; export type CreateTssStageRequest = Pick< TssStage, diff --git a/crypto/teddsa/api_lib/src/index.ts b/crypto/teddsa/api_lib/src/index.ts index f608e1ed8..78aa4f2c3 100644 --- a/crypto/teddsa/api_lib/src/index.ts +++ b/crypto/teddsa/api_lib/src/index.ts @@ -6,10 +6,6 @@ import type { SignEd25519Round2Response, SignEd25519AggregateBody, SignEd25519AggregateResponse, - PresignEd25519Body, - PresignEd25519Response, - SignEd25519Body, - SignEd25519Response, } from "@oko-wallet/oko-types/tss"; import type { SignInResponse } from "@oko-wallet/oko-types/user"; import type { @@ -178,33 +174,3 @@ export async function reqSignEd25519Aggregate( ); return resp; } - -export async function reqPresignEd25519( - endpoint: string, - payload: PresignEd25519Body, - apiKey: string, - authToken: string, -) { - const resp: OkoApiResponse = await makePostRequest( - endpoint, - "presign_ed25519", - payload, - authToken, - apiKey, - ); - return resp; -} - -export async function reqSignEd25519( - endpoint: string, - payload: SignEd25519Body, - authToken: string, -) { - const resp: OkoApiResponse = await makePostRequest( - endpoint, - "sign_ed25519", - payload, - authToken, - ); - return resp; -} diff --git a/crypto/teddsa/api_lib/tsconfig.json b/crypto/teddsa/api_lib/tsconfig.json index c8c92cbd6..1b280ecd1 100644 --- a/crypto/teddsa/api_lib/tsconfig.json +++ b/crypto/teddsa/api_lib/tsconfig.json @@ -1,8 +1,17 @@ { - "extends": "../../../tsconfig.json", "compilerOptions": { - "outDir": "./dist", - "rootDir": "./src" + "outDir": "dist", + "sourceMap": true, + "target": "esnext", + "module": "esnext", + "moduleResolution": "bundler", + "esModuleInterop": true, + "verbatimModuleSyntax": true, + "forceConsistentCasingInFileNames": true, + "noImplicitAny": true, + "strict": true, + "skipLibCheck": true, + "noEmit": true }, - "include": ["src/**/*"] + "include": ["./*.js", "src/**/*.ts"] } diff --git a/crypto/teddsa/teddsa_addon/addon/index.d.ts b/crypto/teddsa/teddsa_addon/addon/index.d.ts index 9929abd1b..5f78ce633 100644 --- a/crypto/teddsa/teddsa_addon/addon/index.d.ts +++ b/crypto/teddsa/teddsa_addon/addon/index.d.ts @@ -19,6 +19,17 @@ export interface NapiCentralizedKeygenOutput { export declare function napiKeygenCentralizedEd25519(): NapiCentralizedKeygenOutput /** Import an existing Ed25519 secret key and split it into threshold shares. */ export declare function napiKeygenImportEd25519(secretKey: Array): NapiCentralizedKeygenOutput +/** Extract signing_share and verifying_share from a serialized key_package. */ +export interface NapiKeyPackageShares { + signing_share: Array + verifying_share: Array +} +/** Extract signing_share and verifying_share from a serialized Ed25519 key_package. */ +export declare function napiExtractKeyPackageSharesEd25519(keyPackageBytes: Array): NapiKeyPackageShares +/** Reconstruct a key_package from signing_share, verifying_share, identifier, and verifying_key. */ +export declare function napiReconstructKeyPackageEd25519(signingShare: Array, verifyingShare: Array, identifier: Array, verifyingKey: Array, minSigners: number): Array +/** Reconstruct a public_key_package from verifying_shares, identifiers, and verifying_key. */ +export declare function napiReconstructPublicKeyPackageEd25519(clientVerifyingShare: Array, clientIdentifier: Array, serverVerifyingShare: Array, serverIdentifier: Array, verifyingKey: Array): Array /** Output from a signing round 1 (commitment) */ export interface NapiSigningCommitmentOutput { nonces: Array diff --git a/crypto/teddsa/teddsa_addon/addon/index.js b/crypto/teddsa/teddsa_addon/addon/index.js index 115a4f1d0..779f42f18 100644 --- a/crypto/teddsa/teddsa_addon/addon/index.js +++ b/crypto/teddsa/teddsa_addon/addon/index.js @@ -310,10 +310,13 @@ if (!nativeBinding) { throw new Error(`Failed to load native binding`) } -const { napiKeygenCentralizedEd25519, napiKeygenImportEd25519, napiSignRound1Ed25519, napiSignRound2Ed25519, napiAggregateEd25519, napiVerifyEd25519 } = nativeBinding +const { napiKeygenCentralizedEd25519, napiKeygenImportEd25519, napiExtractKeyPackageSharesEd25519, napiReconstructKeyPackageEd25519, napiReconstructPublicKeyPackageEd25519, napiSignRound1Ed25519, napiSignRound2Ed25519, napiAggregateEd25519, napiVerifyEd25519 } = nativeBinding module.exports.napiKeygenCentralizedEd25519 = napiKeygenCentralizedEd25519 module.exports.napiKeygenImportEd25519 = napiKeygenImportEd25519 +module.exports.napiExtractKeyPackageSharesEd25519 = napiExtractKeyPackageSharesEd25519 +module.exports.napiReconstructKeyPackageEd25519 = napiReconstructKeyPackageEd25519 +module.exports.napiReconstructPublicKeyPackageEd25519 = napiReconstructPublicKeyPackageEd25519 module.exports.napiSignRound1Ed25519 = napiSignRound1Ed25519 module.exports.napiSignRound2Ed25519 = napiSignRound2Ed25519 module.exports.napiAggregateEd25519 = napiAggregateEd25519 diff --git a/crypto/teddsa/teddsa_addon/addon/src/keygen.rs b/crypto/teddsa/teddsa_addon/addon/src/keygen.rs index b10ac33a9..3a9b36c5b 100644 --- a/crypto/teddsa/teddsa_addon/addon/src/keygen.rs +++ b/crypto/teddsa/teddsa_addon/addon/src/keygen.rs @@ -64,7 +64,9 @@ fn keygen_centralized_inner() -> std::result::Result std::result::Result { +fn keygen_import_inner( + secret: [u8; 32], +) -> std::result::Result { let mut rng = OsRng; let max_signers = 2; let min_signers = 2; @@ -136,3 +138,168 @@ pub fn napi_keygen_import_ed25519(secret_key: Vec) -> Result, + #[napi(js_name = "verifying_share")] + pub verifying_share: Vec, +} + +/// Extract signing_share and verifying_share from a serialized Ed25519 key_package. +#[napi] +pub fn napi_extract_key_package_shares_ed25519( + key_package_bytes: Vec, +) -> Result { + let key_package = KeyPackage::deserialize(&key_package_bytes).map_err(|e| { + napi::Error::new( + napi::Status::GenericFailure, + format!("Failed to deserialize key_package: {:?}", e), + ) + })?; + + let signing_share_bytes = key_package.signing_share().serialize(); + let verifying_share_bytes = key_package + .verifying_share() + .serialize() + .map_err(|e| { + napi::Error::new( + napi::Status::GenericFailure, + format!("Failed to serialize verifying_share: {:?}", e), + ) + })? + .to_vec(); + + Ok(NapiKeyPackageShares { + signing_share: signing_share_bytes.to_vec(), + verifying_share: verifying_share_bytes, + }) +} + +/// Reconstruct a key_package from signing_share, verifying_share, identifier, and verifying_key. +#[napi] +pub fn napi_reconstruct_key_package_ed25519( + signing_share: Vec, + verifying_share: Vec, + identifier: Vec, + verifying_key: Vec, + min_signers: u16, +) -> Result> { + use frost::keys::{SigningShare, VerifyingShare}; + use frost::Identifier; + use frost::VerifyingKey; + + let identifier = Identifier::deserialize(&identifier).map_err(|e| { + napi::Error::new( + napi::Status::GenericFailure, + format!("Failed to deserialize identifier: {:?}", e), + ) + })?; + + let signing_share = SigningShare::deserialize(&signing_share).map_err(|e| { + napi::Error::new( + napi::Status::GenericFailure, + format!("Failed to deserialize signing_share: {:?}", e), + ) + })?; + + let verifying_share = VerifyingShare::deserialize(&verifying_share).map_err(|e| { + napi::Error::new( + napi::Status::GenericFailure, + format!("Failed to deserialize verifying_share: {:?}", e), + ) + })?; + + let verifying_key = VerifyingKey::deserialize(&verifying_key).map_err(|e| { + napi::Error::new( + napi::Status::GenericFailure, + format!("Failed to deserialize verifying_key: {:?}", e), + ) + })?; + + let key_package = KeyPackage::new( + identifier, + signing_share, + verifying_share, + verifying_key, + min_signers, + ); + + let key_package_bytes = key_package.serialize().map_err(|e| { + napi::Error::new( + napi::Status::GenericFailure, + format!("Failed to serialize key_package: {:?}", e), + ) + })?; + + Ok(key_package_bytes) +} + +/// Reconstruct a public_key_package from verifying_shares, identifiers, and verifying_key. +#[napi] +pub fn napi_reconstruct_public_key_package_ed25519( + client_verifying_share: Vec, + client_identifier: Vec, + server_verifying_share: Vec, + server_identifier: Vec, + verifying_key: Vec, +) -> Result> { + use frost::keys::{PublicKeyPackage, VerifyingShare}; + use frost::Identifier; + use frost::VerifyingKey; + use std::collections::BTreeMap; + + let client_identifier = Identifier::deserialize(&client_identifier).map_err(|e| { + napi::Error::new( + napi::Status::GenericFailure, + format!("Failed to deserialize client_identifier: {:?}", e), + ) + })?; + + let server_identifier = Identifier::deserialize(&server_identifier).map_err(|e| { + napi::Error::new( + napi::Status::GenericFailure, + format!("Failed to deserialize server_identifier: {:?}", e), + ) + })?; + + let client_verifying_share = + VerifyingShare::deserialize(&client_verifying_share).map_err(|e| { + napi::Error::new( + napi::Status::GenericFailure, + format!("Failed to deserialize client_verifying_share: {:?}", e), + ) + })?; + + let server_verifying_share = + VerifyingShare::deserialize(&server_verifying_share).map_err(|e| { + napi::Error::new( + napi::Status::GenericFailure, + format!("Failed to deserialize server_verifying_share: {:?}", e), + ) + })?; + + let verifying_key = VerifyingKey::deserialize(&verifying_key).map_err(|e| { + napi::Error::new( + napi::Status::GenericFailure, + format!("Failed to deserialize verifying_key: {:?}", e), + ) + })?; + + let mut verifying_shares: BTreeMap = BTreeMap::new(); + verifying_shares.insert(client_identifier, client_verifying_share); + verifying_shares.insert(server_identifier, server_verifying_share); + + let public_key_package = PublicKeyPackage::new(verifying_shares, verifying_key); + + let public_key_package_bytes = public_key_package.serialize().map_err(|e| { + napi::Error::new( + napi::Status::GenericFailure, + format!("Failed to serialize public_key_package: {:?}", e), + ) + })?; + + Ok(public_key_package_bytes) +} diff --git a/crypto/teddsa/teddsa_addon/addon/teddsa-addon.darwin-arm64.node b/crypto/teddsa/teddsa_addon/addon/teddsa-addon.darwin-arm64.node index f0b9be05377f47010920235a091b37d2bcf74c32..e1abb4b8d8df9c904ea1c6e27c759c2f97e004c3 100755 GIT binary patch delta 161701 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
Iy$EnT>4ucmMZn_2pX{ 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�Rl}4VbyT-#W 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 YSFBt8*@o)-mhyP%Rfop{Ms8jGA3G?OssI20 delta 145782 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 diff --git a/crypto/teddsa/teddsa_addon/src/server/index.ts b/crypto/teddsa/teddsa_addon/src/server/index.ts index 9c7c73d1a..ad93c8ef4 100644 --- a/crypto/teddsa/teddsa_addon/src/server/index.ts +++ b/crypto/teddsa/teddsa_addon/src/server/index.ts @@ -11,6 +11,9 @@ import { napiSignRound2Ed25519, napiAggregateEd25519, napiVerifyEd25519, + napiExtractKeyPackageSharesEd25519, + napiReconstructKeyPackageEd25519, + napiReconstructPublicKeyPackageEd25519, } from "../../addon/index.js"; // NOTE: NAPI-specific types (serialized bytes format) @@ -41,6 +44,11 @@ export interface NapiSignatureOutput { signature: number[]; } +export interface NapiKeyPackageShares { + signing_share: number[]; + verifying_share: number[]; +} + export function runKeygenCentralizedEd25519(): NapiCentralizedKeygenOutput { return napiKeygenCentralizedEd25519(); } @@ -96,3 +104,45 @@ export function runVerifyEd25519( Array.from(publicKeyPackage), ); } + +export function extractKeyPackageSharesEd25519( + keyPackage: Uint8Array, +): NapiKeyPackageShares { + return napiExtractKeyPackageSharesEd25519(Array.from(keyPackage)); +} + +export function reconstructKeyPackageEd25519( + signingShare: Uint8Array, + verifyingShare: Uint8Array, + identifier: Uint8Array, + verifyingKey: Uint8Array, + minSigners: number, +): Uint8Array { + return new Uint8Array( + napiReconstructKeyPackageEd25519( + Array.from(signingShare), + Array.from(verifyingShare), + Array.from(identifier), + Array.from(verifyingKey), + minSigners, + ), + ); +} + +export function reconstructPublicKeyPackageEd25519( + clientVerifyingShare: Uint8Array, + clientIdentifier: Uint8Array, + serverVerifyingShare: Uint8Array, + serverIdentifier: Uint8Array, + verifyingKey: Uint8Array, +): Uint8Array { + return new Uint8Array( + napiReconstructPublicKeyPackageEd25519( + Array.from(clientVerifyingShare), + Array.from(clientIdentifier), + Array.from(serverVerifyingShare), + Array.from(serverIdentifier), + Array.from(verifyingKey), + ), + ); +} diff --git a/crypto/teddsa/teddsa_addon/src/tests/keygen.test.ts b/crypto/teddsa/teddsa_addon/src/tests/keygen.test.ts index 95460b2d8..8e07204aa 100644 --- a/crypto/teddsa/teddsa_addon/src/tests/keygen.test.ts +++ b/crypto/teddsa/teddsa_addon/src/tests/keygen.test.ts @@ -1,6 +1,12 @@ import { Participant } from "@oko-wallet/teddsa-interface"; -import { runKeygenCentralizedEd25519, runKeygenImportEd25519 } from "../server"; +import { + runKeygenCentralizedEd25519, + runKeygenImportEd25519, + extractKeyPackageSharesEd25519, + reconstructPublicKeyPackageEd25519, + reconstructKeyPackageEd25519, +} from "../server"; export async function keygenCentralizedTest() { console.log("Testing centralized keygen...\n"); @@ -353,6 +359,562 @@ export async function keygenCentralizedConsistencyTest() { console.log("Consistency test passed"); } +export async function extractKeyPackageSharesTest() { + console.log("\nTesting extractKeyPackageSharesEd25519...\n"); + + // Generate a key_package first + const keygenOutput = runKeygenCentralizedEd25519(); + const clientKeyPackage = new Uint8Array( + keygenOutput.keygen_outputs[Participant.P0].key_package, + ); + const serverKeyPackage = new Uint8Array( + keygenOutput.keygen_outputs[Participant.P1].key_package, + ); + + // Extract shares from client key_package + const clientShares = extractKeyPackageSharesEd25519(clientKeyPackage); + + // Validate output structure + if (!clientShares.signing_share || clientShares.signing_share.length !== 32) { + throw new Error( + `Expected 32-byte signing_share, got ${clientShares.signing_share?.length ?? 0} bytes`, + ); + } + + if ( + !clientShares.verifying_share || + clientShares.verifying_share.length !== 32 + ) { + throw new Error( + `Expected 32-byte verifying_share, got ${clientShares.verifying_share?.length ?? 0} bytes`, + ); + } + + console.log(" ✓ Client shares extracted successfully"); + console.log(` ✓ Signing share: ${clientShares.signing_share.length} bytes`); + console.log( + ` ✓ Verifying share: ${clientShares.verifying_share.length} bytes`, + ); + + // Extract shares from server key_package + const serverShares = extractKeyPackageSharesEd25519(serverKeyPackage); + + // Validate server shares + if (!serverShares.signing_share || serverShares.signing_share.length !== 32) { + throw new Error( + `Expected 32-byte signing_share, got ${serverShares.signing_share?.length ?? 0} bytes`, + ); + } + + if ( + !serverShares.verifying_share || + serverShares.verifying_share.length !== 32 + ) { + throw new Error( + `Expected 32-byte verifying_share, got ${serverShares.verifying_share?.length ?? 0} bytes`, + ); + } + + console.log(" ✓ Server shares extracted successfully"); + + // Verify that client and server shares are different + const clientSigningShareHex = Buffer.from( + clientShares.signing_share, + ).toString("hex"); + const serverSigningShareHex = Buffer.from( + serverShares.signing_share, + ).toString("hex"); + if (clientSigningShareHex === serverSigningShareHex) { + throw new Error("Client and server signing shares should be different"); + } + + const clientVerifyingShareHex = Buffer.from( + clientShares.verifying_share, + ).toString("hex"); + const serverVerifyingShareHex = Buffer.from( + serverShares.verifying_share, + ).toString("hex"); + if (clientVerifyingShareHex === serverVerifyingShareHex) { + throw new Error("Client and server verifying shares should be different"); + } + + console.log(" ✓ Client and server shares are different"); + + // Test with invalid key_package + try { + const invalidKeyPackage = new Uint8Array(32).fill(0xff); + extractKeyPackageSharesEd25519(invalidKeyPackage); + throw new Error("Should have thrown an error for invalid key_package"); + } catch (error: any) { + if ( + !error.message?.includes("deserialize") && + !error.message?.includes("Failed to deserialize") + ) { + throw new Error( + `Unexpected error for invalid key_package: ${error.message}`, + ); + } + console.log(" ✓ Invalid key_package correctly rejected"); + } + + // Test consistency: extract from same key_package multiple times + const shares1 = extractKeyPackageSharesEd25519(clientKeyPackage); + const shares2 = extractKeyPackageSharesEd25519(clientKeyPackage); + + const signingShare1Hex = Buffer.from(shares1.signing_share).toString("hex"); + const signingShare2Hex = Buffer.from(shares2.signing_share).toString("hex"); + if (signingShare1Hex !== signingShare2Hex) { + throw new Error("Extraction should be deterministic"); + } + + const verifyingShare1Hex = Buffer.from(shares1.verifying_share).toString( + "hex", + ); + const verifyingShare2Hex = Buffer.from(shares2.verifying_share).toString( + "hex", + ); + if (verifyingShare1Hex !== verifyingShare2Hex) { + throw new Error("Extraction should be deterministic"); + } + + console.log(" ✓ Extraction is deterministic"); + + console.log("\nExtract key package shares test passed"); +} + +export async function reconstructPublicKeyPackageTest() { + console.log("\nTesting reconstructPublicKeyPackageEd25519...\n"); + + // Generate a keygen output to get the original public_key_package + const keygenOutput = runKeygenCentralizedEd25519(); + const originalPublicKeyPackage = new Uint8Array( + keygenOutput.keygen_outputs[Participant.P0].public_key_package, + ); + + // Extract verifying_shares and identifiers from key_packages + const clientKeyPackage = new Uint8Array( + keygenOutput.keygen_outputs[Participant.P0].key_package, + ); + const serverKeyPackage = new Uint8Array( + keygenOutput.keygen_outputs[Participant.P1].key_package, + ); + + const clientShares = extractKeyPackageSharesEd25519(clientKeyPackage); + const serverShares = extractKeyPackageSharesEd25519(serverKeyPackage); + + const clientIdentifier = new Uint8Array( + keygenOutput.keygen_outputs[Participant.P0].identifier, + ); + const serverIdentifier = new Uint8Array( + keygenOutput.keygen_outputs[Participant.P1].identifier, + ); + const verifyingKey = new Uint8Array(keygenOutput.public_key); + + // Reconstruct public_key_package + const reconstructedPublicKeyPackage = reconstructPublicKeyPackageEd25519( + new Uint8Array(clientShares.verifying_share), + clientIdentifier, + new Uint8Array(serverShares.verifying_share), + serverIdentifier, + verifyingKey, + ); + + // Validate output structure + if ( + !reconstructedPublicKeyPackage || + reconstructedPublicKeyPackage.length === 0 + ) { + throw new Error("Reconstructed public_key_package is empty"); + } + + console.log( + ` ✓ Public key package reconstructed: ${reconstructedPublicKeyPackage.length} bytes`, + ); + + // Compare with original public_key_package + const originalHex = Buffer.from(originalPublicKeyPackage).toString("hex"); + const reconstructedHex = Buffer.from(reconstructedPublicKeyPackage).toString( + "hex", + ); + + if (originalHex !== reconstructedHex) { + throw new Error( + "Reconstructed public_key_package should match original public_key_package", + ); + } + + console.log(" ✓ Reconstructed public_key_package matches original"); + + // Test consistency: reconstruct multiple times should produce same result + const reconstructed1 = reconstructPublicKeyPackageEd25519( + new Uint8Array(clientShares.verifying_share), + clientIdentifier, + new Uint8Array(serverShares.verifying_share), + serverIdentifier, + verifyingKey, + ); + const reconstructed2 = reconstructPublicKeyPackageEd25519( + new Uint8Array(clientShares.verifying_share), + clientIdentifier, + new Uint8Array(serverShares.verifying_share), + serverIdentifier, + verifyingKey, + ); + + const reconstructed1Hex = Buffer.from(reconstructed1).toString("hex"); + const reconstructed2Hex = Buffer.from(reconstructed2).toString("hex"); + + if (reconstructed1Hex !== reconstructed2Hex) { + throw new Error("Reconstruction should be deterministic"); + } + + console.log(" ✓ Reconstruction is deterministic"); + + // Test with invalid verifying_share (wrong length) + try { + const invalidVerifyingShare = new Uint8Array(31).fill(0xff); + reconstructPublicKeyPackageEd25519( + invalidVerifyingShare, + clientIdentifier, + new Uint8Array(serverShares.verifying_share), + serverIdentifier, + verifyingKey, + ); + throw new Error("Should have thrown an error for invalid verifying_share"); + } catch (error: any) { + if ( + !error.message?.includes("deserialize") && + !error.message?.includes("Failed to deserialize") && + !error.message?.includes("Invalid") + ) { + throw new Error( + `Unexpected error for invalid verifying_share: ${error.message}`, + ); + } + console.log(" ✓ Invalid verifying_share correctly rejected"); + } + + // Test with invalid identifier (wrong length) + try { + const invalidIdentifier = new Uint8Array(31).fill(0xff); + reconstructPublicKeyPackageEd25519( + new Uint8Array(clientShares.verifying_share), + invalidIdentifier, + new Uint8Array(serverShares.verifying_share), + serverIdentifier, + verifyingKey, + ); + throw new Error("Should have thrown an error for invalid identifier"); + } catch (error: any) { + if ( + !error.message?.includes("deserialize") && + !error.message?.includes("Failed to deserialize") && + !error.message?.includes("Invalid") + ) { + throw new Error( + `Unexpected error for invalid identifier: ${error.message}`, + ); + } + console.log(" ✓ Invalid identifier correctly rejected"); + } + + // Test with invalid verifying_key (wrong length) + try { + const invalidVerifyingKey = new Uint8Array(31).fill(0xff); + reconstructPublicKeyPackageEd25519( + new Uint8Array(clientShares.verifying_share), + clientIdentifier, + new Uint8Array(serverShares.verifying_share), + serverIdentifier, + invalidVerifyingKey, + ); + throw new Error("Should have thrown an error for invalid verifying_key"); + } catch (error: any) { + if ( + !error.message?.includes("deserialize") && + !error.message?.includes("Failed to deserialize") && + !error.message?.includes("Invalid") + ) { + throw new Error( + `Unexpected error for invalid verifying_key: ${error.message}`, + ); + } + console.log(" ✓ Invalid verifying_key correctly rejected"); + } + + // Test with swapped identifiers (should produce same result since BTreeMap orders by identifier) + const swappedPublicKeyPackage = reconstructPublicKeyPackageEd25519( + new Uint8Array(serverShares.verifying_share), + serverIdentifier, + new Uint8Array(clientShares.verifying_share), + clientIdentifier, + verifyingKey, + ); + + const swappedHex = Buffer.from(swappedPublicKeyPackage).toString("hex"); + if (swappedHex !== originalHex) { + throw new Error( + "Swapped identifiers should produce same public_key_package (BTreeMap orders by identifier)", + ); + } + + console.log( + " ✓ Swapped identifiers produce same package (BTreeMap ordering)", + ); + + console.log("\nReconstruct public key package test passed"); +} + +export async function reconstructKeyPackageTest() { + console.log("\nTesting reconstructKeyPackageEd25519...\n"); + + // Generate a keygen output to get the original key_package + const keygenOutput = runKeygenCentralizedEd25519(); + const originalClientKeyPackage = new Uint8Array( + keygenOutput.keygen_outputs[Participant.P0].key_package, + ); + const originalServerKeyPackage = new Uint8Array( + keygenOutput.keygen_outputs[Participant.P1].key_package, + ); + + // Extract shares from key_packages + const clientShares = extractKeyPackageSharesEd25519(originalClientKeyPackage); + const serverShares = extractKeyPackageSharesEd25519(originalServerKeyPackage); + + const clientIdentifier = new Uint8Array( + keygenOutput.keygen_outputs[Participant.P0].identifier, + ); + const serverIdentifier = new Uint8Array( + keygenOutput.keygen_outputs[Participant.P1].identifier, + ); + const verifyingKey = new Uint8Array(keygenOutput.public_key); + const minSigners = 2; + + // Reconstruct client key_package + const reconstructedClientKeyPackage = reconstructKeyPackageEd25519( + new Uint8Array(clientShares.signing_share), + new Uint8Array(clientShares.verifying_share), + clientIdentifier, + verifyingKey, + minSigners, + ); + + // Validate output structure + if ( + !reconstructedClientKeyPackage || + reconstructedClientKeyPackage.length === 0 + ) { + throw new Error("Reconstructed client key_package is empty"); + } + + console.log( + ` ✓ Client key package reconstructed: ${reconstructedClientKeyPackage.length} bytes`, + ); + + // Compare with original client key_package + const originalClientHex = Buffer.from(originalClientKeyPackage).toString( + "hex", + ); + const reconstructedClientHex = Buffer.from( + reconstructedClientKeyPackage, + ).toString("hex"); + + if (originalClientHex !== reconstructedClientHex) { + throw new Error( + "Reconstructed client key_package should match original client key_package", + ); + } + + console.log(" ✓ Reconstructed client key_package matches original"); + + // Reconstruct server key_package + const reconstructedServerKeyPackage = reconstructKeyPackageEd25519( + new Uint8Array(serverShares.signing_share), + new Uint8Array(serverShares.verifying_share), + serverIdentifier, + verifyingKey, + minSigners, + ); + + // Validate server key_package + if ( + !reconstructedServerKeyPackage || + reconstructedServerKeyPackage.length === 0 + ) { + throw new Error("Reconstructed server key_package is empty"); + } + + const originalServerHex = Buffer.from(originalServerKeyPackage).toString( + "hex", + ); + const reconstructedServerHex = Buffer.from( + reconstructedServerKeyPackage, + ).toString("hex"); + + if (originalServerHex !== reconstructedServerHex) { + throw new Error( + "Reconstructed server key_package should match original server key_package", + ); + } + + console.log(" ✓ Reconstructed server key_package matches original"); + + // Verify client and server key_packages are different + if (reconstructedClientHex === reconstructedServerHex) { + throw new Error( + "Client and server key_packages should be different (different identifiers and shares)", + ); + } + + console.log(" ✓ Client and server key_packages are different"); + + // Test consistency: reconstruct multiple times should produce same result + const reconstructed1 = reconstructKeyPackageEd25519( + new Uint8Array(clientShares.signing_share), + new Uint8Array(clientShares.verifying_share), + clientIdentifier, + verifyingKey, + minSigners, + ); + const reconstructed2 = reconstructKeyPackageEd25519( + new Uint8Array(clientShares.signing_share), + new Uint8Array(clientShares.verifying_share), + clientIdentifier, + verifyingKey, + minSigners, + ); + + const reconstructed1Hex = Buffer.from(reconstructed1).toString("hex"); + const reconstructed2Hex = Buffer.from(reconstructed2).toString("hex"); + + if (reconstructed1Hex !== reconstructed2Hex) { + throw new Error("Reconstruction should be deterministic"); + } + + console.log(" ✓ Reconstruction is deterministic"); + + // Test with invalid signing_share (wrong length) + try { + const invalidSigningShare = new Uint8Array(31).fill(0xff); + reconstructKeyPackageEd25519( + invalidSigningShare, + new Uint8Array(clientShares.verifying_share), + clientIdentifier, + verifyingKey, + minSigners, + ); + throw new Error("Should have thrown an error for invalid signing_share"); + } catch (error: any) { + if ( + !error.message?.includes("deserialize") && + !error.message?.includes("Failed to deserialize") && + !error.message?.includes("Invalid") + ) { + throw new Error( + `Unexpected error for invalid signing_share: ${error.message}`, + ); + } + console.log(" ✓ Invalid signing_share correctly rejected"); + } + + // Test with invalid verifying_share (wrong length) + try { + const invalidVerifyingShare = new Uint8Array(31).fill(0xff); + reconstructKeyPackageEd25519( + new Uint8Array(clientShares.signing_share), + invalidVerifyingShare, + clientIdentifier, + verifyingKey, + minSigners, + ); + throw new Error("Should have thrown an error for invalid verifying_share"); + } catch (error: any) { + if ( + !error.message?.includes("deserialize") && + !error.message?.includes("Failed to deserialize") && + !error.message?.includes("Invalid") + ) { + throw new Error( + `Unexpected error for invalid verifying_share: ${error.message}`, + ); + } + console.log(" ✓ Invalid verifying_share correctly rejected"); + } + + // Test with invalid identifier (wrong length) + try { + const invalidIdentifier = new Uint8Array(31).fill(0xff); + reconstructKeyPackageEd25519( + new Uint8Array(clientShares.signing_share), + new Uint8Array(clientShares.verifying_share), + invalidIdentifier, + verifyingKey, + minSigners, + ); + throw new Error("Should have thrown an error for invalid identifier"); + } catch (error: any) { + if ( + !error.message?.includes("deserialize") && + !error.message?.includes("Failed to deserialize") && + !error.message?.includes("Invalid") + ) { + throw new Error( + `Unexpected error for invalid identifier: ${error.message}`, + ); + } + console.log(" ✓ Invalid identifier correctly rejected"); + } + + // Test with invalid verifying_key (wrong length) + try { + const invalidVerifyingKey = new Uint8Array(31).fill(0xff); + reconstructKeyPackageEd25519( + new Uint8Array(clientShares.signing_share), + new Uint8Array(clientShares.verifying_share), + clientIdentifier, + invalidVerifyingKey, + minSigners, + ); + throw new Error("Should have thrown an error for invalid verifying_key"); + } catch (error: any) { + if ( + !error.message?.includes("deserialize") && + !error.message?.includes("Failed to deserialize") && + !error.message?.includes("Invalid") + ) { + throw new Error( + `Unexpected error for invalid verifying_key: ${error.message}`, + ); + } + console.log(" ✓ Invalid verifying_key correctly rejected"); + } + + const mismatchedKeyPackage = reconstructKeyPackageEd25519( + new Uint8Array(clientShares.signing_share), + new Uint8Array(clientShares.verifying_share), + serverIdentifier, // Using server identifier with client shares + verifyingKey, + minSigners, + ); + + if (mismatchedKeyPackage.length === 0) { + throw new Error( + "Mismatched components should still produce valid key_package", + ); + } + + const mismatchedHex = Buffer.from(mismatchedKeyPackage).toString("hex"); + if (mismatchedHex === originalClientHex) { + throw new Error( + "Mismatched identifier should produce different key_package", + ); + } + + console.log(" ✓ Mismatched components produce different key_package"); + + console.log("\nReconstruct key package test passed"); +} + // Run the tests async function main() { console.log("Starting Ed25519 keygen tests...\n"); @@ -366,6 +928,9 @@ async function main() { await keygenImportErrorTest(); await keygenImportEdgeCasesTest(); await keygenCentralizedConsistencyTest(); + await extractKeyPackageSharesTest(); + await reconstructKeyPackageTest(); + await reconstructPublicKeyPackageTest(); console.log("\n" + "=".repeat(50)); console.log("All keygen tests passed!"); diff --git a/crypto/teddsa/teddsa_hooks/package.json b/crypto/teddsa/teddsa_hooks/package.json index 744efbca8..9f2b0c40e 100644 --- a/crypto/teddsa/teddsa_hooks/package.json +++ b/crypto/teddsa/teddsa_hooks/package.json @@ -6,6 +6,7 @@ "@oko-wallet/bytes": "^0.0.3-alpha.65", "@oko-wallet/frost-ed25519-keplr-wasm": "workspace:*", "@oko-wallet/stdlib-js": "^0.0.2-rc.42", + "@oko-wallet/teddsa-api-lib": "workspace:*", "@oko-wallet/teddsa-interface": "workspace:*", "@oko-wallet/teddsa-wasm-mock": "workspace:*" }, diff --git a/crypto/teddsa/teddsa_hooks/src/sign.ts b/crypto/teddsa/teddsa_hooks/src/sign.ts index 786a69106..c67f26400 100644 --- a/crypto/teddsa/teddsa_hooks/src/sign.ts +++ b/crypto/teddsa/teddsa_hooks/src/sign.ts @@ -9,6 +9,11 @@ import type { KeyPackageRaw, PublicKeyPackageRaw, } from "@oko-wallet/teddsa-interface"; +import { + reqSignEd25519Round1, + reqSignEd25519Round2, + reqSignEd25519Aggregate, +} from "@oko-wallet/teddsa-api-lib"; import type { TeddsaKeygenOutputBytes } from "./types"; @@ -104,6 +109,134 @@ export function teddsaVerify( } } +export async function runTeddsaSign( + endpoint: string, + message: Uint8Array, + keyPackage: KeyPackageRaw, + authToken: string, + getIsAborted: () => boolean, +): Promise> { + if (getIsAborted()) { + return { success: false, err: { type: "aborted" } }; + } + + // Round 1: Generate client commitments locally + const round1Result = teddsaSignRound1(keyPackage); + if (!round1Result.success) { + return { success: false, err: { type: "error", msg: round1Result.err } }; + } + + const clientCommitment: CommitmentEntry = { + identifier: round1Result.data.identifier, + commitments: round1Result.data.commitments, + }; + + // Send message to server to initiate Round 1 and get server commitments + if (getIsAborted()) { + return { success: false, err: { type: "aborted" } }; + } + + const round1Resp = await reqSignEd25519Round1( + endpoint, + { msg: [...message] }, + authToken, + ); + if (round1Resp.success === false) { + return { + success: false, + err: { type: "error", msg: round1Resp.msg }, + }; + } + + const { session_id: sessionId, commitments_0: serverCommitment } = + round1Resp.data; + + // Combine and sort commitments by identifier + const allCommitments: CommitmentEntry[] = [ + clientCommitment, + serverCommitment, + ].sort((a, b) => (a.identifier[0] ?? 0) - (b.identifier[0] ?? 0)); + + // Round 2: Send client commitments to server and get server signature share + if (getIsAborted()) { + return { success: false, err: { type: "aborted" } }; + } + + const round2Resp = await reqSignEd25519Round2( + endpoint, + { + session_id: sessionId, + commitments_1: clientCommitment, + }, + authToken, + ); + if (round2Resp.success === false) { + return { + success: false, + err: { type: "error", msg: round2Resp.msg }, + }; + } + + const serverSignatureShare: SignatureShareEntry = + round2Resp.data.signature_share_0; + + // Generate client signature share locally + if (getIsAborted()) { + return { success: false, err: { type: "aborted" } }; + } + + const round2Result = teddsaSignRound2( + message, + keyPackage, + new Uint8Array(round1Result.data.nonces), + allCommitments, + ); + if (!round2Result.success) { + return { success: false, err: { type: "error", msg: round2Result.err } }; + } + + const clientSignatureShare: SignatureShareEntry = { + identifier: round2Result.data.identifier, + signature_share: round2Result.data.signature_share, + }; + + // Combine and sort signature shares by identifier + const allSignatureShares: SignatureShareEntry[] = [ + clientSignatureShare, + serverSignatureShare, + ].sort((a, b) => (a.identifier[0] ?? 0) - (b.identifier[0] ?? 0)); + + // Aggregate: Send all data to server to get final signature + if (getIsAborted()) { + return { success: false, err: { type: "aborted" } }; + } + + // Extract user_verifying_share from keyPackage + const userVerifyingShare = keyPackage.verifying_share; + + const aggregateResp = await reqSignEd25519Aggregate( + endpoint, + { + session_id: sessionId, + msg: [...message], + all_commitments: allCommitments, + all_signature_shares: allSignatureShares, + user_verifying_share: userVerifyingShare, + }, + authToken, + ); + if (aggregateResp.success === false) { + return { + success: false, + err: { type: "error", msg: aggregateResp.msg }, + }; + } + + const signature = new Uint8Array(aggregateResp.data.signature); + + return { success: true, data: signature }; +} + export async function runTeddsaSignLocal( message: Uint8Array, keygen1: TeddsaKeygenOutputBytes, diff --git a/embed/oko_attached/src/crypto/sign_ed25519.ts b/embed/oko_attached/src/crypto/sign_ed25519.ts index 486991b65..be595f226 100644 --- a/embed/oko_attached/src/crypto/sign_ed25519.ts +++ b/embed/oko_attached/src/crypto/sign_ed25519.ts @@ -11,7 +11,6 @@ import type { } from "@oko-wallet/teddsa-interface"; import type { Result } from "@oko-wallet/stdlib-js"; import type { MakeSignOutputError } from "@oko-wallet/oko-sdk-core"; -import { reqPresignEd25519, reqSignEd25519 } from "@oko-wallet/teddsa-api-lib"; import { TSS_V1_ENDPOINT } from "@oko-wallet-attached/requests/oko_api"; @@ -29,131 +28,133 @@ export async function makeSignOutputEd25519( getIsAborted: () => boolean, ): Promise> { try { - if (getIsAborted()) { - return { success: false, err: { type: "aborted" } }; - } - - const presignRes = await reqPresignEd25519( - TSS_V1_ENDPOINT, - {}, - apiKey, - authToken, - ); - - if (!presignRes.success) { - return { - success: false, - err: { - type: "sign_fail", - error: { type: "error", msg: presignRes.msg }, - }, - }; - } - - const { session_id: sessionId, commitments_0: serverCommitment } = - presignRes.data; - - if (getIsAborted()) { - return { success: false, err: { type: "aborted" } }; - } - - const round1Result = teddsaSignRound1(keyPackage.keyPackage); - if (!round1Result.success) { - return { - success: false, - err: { - type: "sign_fail", - error: { type: "error", msg: round1Result.err }, - }, - }; - } - - const clientCommitment: CommitmentEntry = { - identifier: round1Result.data.identifier, - commitments: round1Result.data.commitments, - }; - - const allCommitments: CommitmentEntry[] = [ - clientCommitment, - serverCommitment, - ].sort((a, b) => (a.identifier[0] ?? 0) - (b.identifier[0] ?? 0)); - - if (getIsAborted()) { - return { success: false, err: { type: "aborted" } }; - } - - const serverSignRes = await reqSignEd25519( - TSS_V1_ENDPOINT, - { - session_id: sessionId, - msg: [...message], - commitments_1: clientCommitment, - }, - authToken, - ); - - if (!serverSignRes.success) { - return { - success: false, - err: { - type: "sign_fail", - error: { type: "error", msg: serverSignRes.msg }, - }, - }; - } - - const serverSignatureShare: SignatureShareEntry = - serverSignRes.data.signature_share_0; - - if (getIsAborted()) { - return { success: false, err: { type: "aborted" } }; - } - - const round2Result = teddsaSignRound2( - message, - keyPackage.keyPackage, - new Uint8Array(round1Result.data.nonces), - allCommitments, - ); - - if (!round2Result.success) { - return { - success: false, - err: { - type: "sign_fail", - error: { type: "error", msg: round2Result.err }, - }, - }; - } - - const clientSignatureShare: SignatureShareEntry = { - identifier: round2Result.data.identifier, - signature_share: round2Result.data.signature_share, - }; - - const allSignatureShares: SignatureShareEntry[] = [ - clientSignatureShare, - serverSignatureShare, - ].sort((a, b) => (a.identifier[0] ?? 0) - (b.identifier[0] ?? 0)); - - const aggregateResult = teddsaAggregate( - message, - allCommitments, - allSignatureShares, - keyPackage.publicKeyPackage, - ); - - if (!aggregateResult.success) { - return { - success: false, - err: { - type: "sign_fail", - error: { type: "error", msg: aggregateResult.err }, - }, - }; - } - - return { success: true, data: aggregateResult.data }; + // @TODO + + // if (getIsAborted()) { + // return { success: false, err: { type: "aborted" } }; + // } + + // const presignRes = await reqPresignEd25519( + // TSS_V1_ENDPOINT, + // {}, + // apiKey, + // authToken, + // ); + + // if (!presignRes.success) { + // return { + // success: false, + // err: { + // type: "sign_fail", + // error: { type: "error", msg: presignRes.msg }, + // }, + // }; + // } + + // const { session_id: sessionId, commitments_0: serverCommitment } = + // presignRes.data; + + // if (getIsAborted()) { + // return { success: false, err: { type: "aborted" } }; + // } + + // const round1Result = teddsaSignRound1(keyPackage.keyPackage); + // if (!round1Result.success) { + // return { + // success: false, + // err: { + // type: "sign_fail", + // error: { type: "error", msg: round1Result.err }, + // }, + // }; + // } + + // const clientCommitment: CommitmentEntry = { + // identifier: round1Result.data.identifier, + // commitments: round1Result.data.commitments, + // }; + + // const allCommitments: CommitmentEntry[] = [ + // clientCommitment, + // serverCommitment, + // ].sort((a, b) => (a.identifier[0] ?? 0) - (b.identifier[0] ?? 0)); + + // if (getIsAborted()) { + // return { success: false, err: { type: "aborted" } }; + // } + + // const serverSignRes = await reqSignEd25519( + // TSS_V1_ENDPOINT, + // { + // session_id: sessionId, + // msg: [...message], + // commitments_1: clientCommitment, + // }, + // authToken, + // ); + + // if (!serverSignRes.success) { + // return { + // success: false, + // err: { + // type: "sign_fail", + // error: { type: "error", msg: serverSignRes.msg }, + // }, + // }; + // } + + // const serverSignatureShare: SignatureShareEntry = + // serverSignRes.data.signature_share_0; + + // if (getIsAborted()) { + // return { success: false, err: { type: "aborted" } }; + // } + + // const round2Result = teddsaSignRound2( + // message, + // keyPackage.keyPackage, + // new Uint8Array(round1Result.data.nonces), + // allCommitments, + // ); + + // if (!round2Result.success) { + // return { + // success: false, + // err: { + // type: "sign_fail", + // error: { type: "error", msg: round2Result.err }, + // }, + // }; + // } + + // const clientSignatureShare: SignatureShareEntry = { + // identifier: round2Result.data.identifier, + // signature_share: round2Result.data.signature_share, + // }; + + // const allSignatureShares: SignatureShareEntry[] = [ + // clientSignatureShare, + // serverSignatureShare, + // ].sort((a, b) => (a.identifier[0] ?? 0) - (b.identifier[0] ?? 0)); + + // const aggregateResult = teddsaAggregate( + // message, + // allCommitments, + // allSignatureShares, + // keyPackage.publicKeyPackage, + // ); + + // if (!aggregateResult.success) { + // return { + // success: false, + // err: { + // type: "sign_fail", + // error: { type: "error", msg: aggregateResult.err }, + // }, + // }; + // } + + return { success: true, data: new Uint8Array(64) }; } catch (error) { return { success: false, diff --git a/yarn.lock b/yarn.lock index 6048684c4..123ab05c2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -11282,7 +11282,7 @@ __metadata: languageName: unknown linkType: soft -"@oko-wallet/teddsa-api-lib@workspace:crypto/teddsa/api_lib": +"@oko-wallet/teddsa-api-lib@workspace:*, @oko-wallet/teddsa-api-lib@workspace:crypto/teddsa/api_lib": version: 0.0.0-use.local resolution: "@oko-wallet/teddsa-api-lib@workspace:crypto/teddsa/api_lib" dependencies: @@ -11311,6 +11311,7 @@ __metadata: "@oko-wallet/bytes": "npm:^0.0.3-alpha.65" "@oko-wallet/frost-ed25519-keplr-wasm": "workspace:*" "@oko-wallet/stdlib-js": "npm:^0.0.2-rc.42" + "@oko-wallet/teddsa-api-lib": "workspace:*" "@oko-wallet/teddsa-interface": "workspace:*" "@oko-wallet/teddsa-wasm-mock": "workspace:*" "@types/node": "npm:^24.10.1" From 7c776d1c950fc0d72c076b3cfbb679e5873d9bcd Mon Sep 17 00:00:00 2001 From: Hyunjae Chung Date: Wed, 14 Jan 2026 15:46:46 +0900 Subject: [PATCH 4/5] customer_dashboard: reset password when it is lost * customer_dashboard: Make email timer configurable * customer_dashboard: Limit forgot password inputs to 16 chars * customer_dashboard: Hardcode email verification timer to 60 * oko_common_ui: fix checkbox icon not visible when data-theme is not set --- .../src/app/users/forgot_password/page.tsx | 72 ++++++++++++++++--- .../reset_password/use_reset_password_form.ts | 16 ++++- .../customer_dashboard/src/constants/index.ts | 4 +- .../src/app/reset_pw_code/page.tsx | 2 +- .../ct_dashboard_api/src/constants/index.ts | 2 + .../src/email/password_reset.ts | 2 +- .../src/routes/customer_auth.ts | 60 ++++++++++++---- .../src/email_verifications/index.ts | 63 ++++++++++++++-- .../openapi/src/ct_dashboard/customer_auth.ts | 24 +++++-- .../src/ct_dashboard/email_verification.ts | 1 + crypto/teddsa/teddsa_interface/tsconfig.json | 4 +- .../src/checkbox/checkbox.module.scss | 7 +- 12 files changed, 211 insertions(+), 46 deletions(-) diff --git a/apps/customer_dashboard/src/app/users/forgot_password/page.tsx b/apps/customer_dashboard/src/app/users/forgot_password/page.tsx index 8444f6541..d1ed3d053 100644 --- a/apps/customer_dashboard/src/app/users/forgot_password/page.tsx +++ b/apps/customer_dashboard/src/app/users/forgot_password/page.tsx @@ -20,6 +20,8 @@ import { EMAIL_REGEX, EMAIL_VERIFICATION_TIMER_SECONDS, PASSWORD_MIN_LENGTH, + PASSWORD_MAX_LENGTH, + PASSWORD_CONTAINS_NUMBER_REGEX, SIX_DIGITS_REGEX, } from "@oko-wallet-ct-dashboard/constants"; import { ExpiryTimer } from "@oko-wallet-ct-dashboard/components/expiry_timer/expiry_timer"; @@ -49,6 +51,7 @@ export default function ForgotPasswordPage() { const [showPassword, setShowPassword] = useState(false); const [showConfirm, setShowConfirm] = useState(false); + const [isCodeExpired, setIsCodeExpired] = useState(false); const codeValue = useMemo(() => codeDigits.join(""), [codeDigits]); @@ -116,6 +119,14 @@ export default function ForgotPasswordPage() { setError(`Password must be at least ${PASSWORD_MIN_LENGTH} characters`); return; } + if (password.length > PASSWORD_MAX_LENGTH) { + setError(`Password must be at most ${PASSWORD_MAX_LENGTH} characters`); + return; + } + if (!PASSWORD_CONTAINS_NUMBER_REGEX.test(password)) { + setError("Password must include at least one number"); + return; + } if (password !== confirmPassword) { setError("Passwords do not match"); return; @@ -123,6 +134,7 @@ export default function ForgotPasswordPage() { setIsLoading(true); resetError(); + setIsCodeExpired(false); try { const res = await requestResetPasswordConfirm( email, @@ -132,7 +144,38 @@ export default function ForgotPasswordPage() { if (res.success) { router.push(paths.home); } else { - setError(res.msg || "Failed to reset password"); + if (res.code === "INVALID_VERIFICATION_CODE") { + setIsCodeExpired(true); + setError("Verification code has expired. Please request a new code."); + } else { + setError(res.msg || "Failed to reset password"); + } + } + } catch (err) { + setError("An unexpected error occurred"); + } finally { + setIsLoading(false); + } + }; + + const handleRequestNewCode = async () => { + if (!email || isLoading) { + return; + } + + setIsLoading(true); + resetError(); + setIsCodeExpired(false); + try { + const res = await requestForgotPassword(email); + if (res.success) { + setCodeDigits(EMPTY_CODE); + setVerifiedCode(""); + setPassword(""); + setConfirmPassword(""); + goToStep(Step.CODE); + } else { + setError(res.msg || "Failed to send code"); } } catch (err) { setError("An unexpected error occurred"); @@ -317,6 +360,7 @@ export default function ForgotPasswordPage() { }} fullWidth requiredSymbol + maxLength={16} helpText={ error ? undefined @@ -344,6 +388,7 @@ export default function ForgotPasswordPage() { }} fullWidth requiredSymbol + maxLength={16} SideComponent={ + {isCodeExpired ? ( + + ) : ( + + )} diff --git a/apps/customer_dashboard/src/components/reset_password/use_reset_password_form.ts b/apps/customer_dashboard/src/components/reset_password/use_reset_password_form.ts index 3729644e0..9fcb6bfb3 100644 --- a/apps/customer_dashboard/src/components/reset_password/use_reset_password_form.ts +++ b/apps/customer_dashboard/src/components/reset_password/use_reset_password_form.ts @@ -3,7 +3,11 @@ import { useForm, type SubmitHandler } from "react-hook-form"; import { useRouter } from "next/navigation"; import { paths } from "@oko-wallet-ct-dashboard/paths"; -import { PASSWORD_MIN_LENGTH } from "@oko-wallet-ct-dashboard/constants"; +import { + PASSWORD_MIN_LENGTH, + PASSWORD_MAX_LENGTH, + PASSWORD_CONTAINS_NUMBER_REGEX, +} from "@oko-wallet-ct-dashboard/constants"; import { requestChangePassword } from "@oko-wallet-ct-dashboard/fetch/users"; import { useAppState } from "@oko-wallet-ct-dashboard/state"; @@ -91,6 +95,16 @@ function resetPasswordResolver(values: ResetPasswordInputs) { type: "minLength", message: `Password must be at least ${PASSWORD_MIN_LENGTH} characters`, }; + } else if (values.newPassword.length > PASSWORD_MAX_LENGTH) { + errors.newPassword = { + type: "maxLength", + message: `Password must be at most ${PASSWORD_MAX_LENGTH} characters`, + }; + } else if (!PASSWORD_CONTAINS_NUMBER_REGEX.test(values.newPassword)) { + errors.newPassword = { + type: "pattern", + message: "Password must include at least one number", + }; } if (!values.confirmPassword) { diff --git a/apps/customer_dashboard/src/constants/index.ts b/apps/customer_dashboard/src/constants/index.ts index 69623fce9..c0b4a6ca0 100644 --- a/apps/customer_dashboard/src/constants/index.ts +++ b/apps/customer_dashboard/src/constants/index.ts @@ -1,8 +1,10 @@ export const EMAIL_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; export const PASSWORD_MIN_LENGTH = 8; +export const PASSWORD_MAX_LENGTH = 16; +export const PASSWORD_CONTAINS_NUMBER_REGEX = /\d/; export const SIX_DIGITS_REGEX = /^\d{6}$/; -export const EMAIL_VERIFICATION_TIMER_SECONDS = 60 * 3; +export const EMAIL_VERIFICATION_TIMER_SECONDS = 60; export const GET_STARTED_URL = "https://form.typeform.com/to/MxrBGq9b"; diff --git a/apps/email_template_2/src/app/reset_pw_code/page.tsx b/apps/email_template_2/src/app/reset_pw_code/page.tsx index 62736b22c..a03f4eee7 100644 --- a/apps/email_template_2/src/app/reset_pw_code/page.tsx +++ b/apps/email_template_2/src/app/reset_pw_code/page.tsx @@ -72,7 +72,7 @@ export default function ResetPwCodePage() { password.
The code is valid for{" "} - {"${email_verification_expiration_minutes}"} minutes + {"${email_verification_expiration_minutes}"} minute for your security. diff --git a/backend/ct_dashboard_api/src/constants/index.ts b/backend/ct_dashboard_api/src/constants/index.ts index 3ffd04649..3ee504128 100644 --- a/backend/ct_dashboard_api/src/constants/index.ts +++ b/backend/ct_dashboard_api/src/constants/index.ts @@ -1,6 +1,8 @@ export const EMAIL_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; export const PASSWORD_MIN_LENGTH = 4; export const CHANGED_PASSWORD_MIN_LENGTH = 8; +export const CHANGED_PASSWORD_MAX_LENGTH = 16; +export const PASSWORD_CONTAINS_NUMBER_REGEX = /\d/; export const SIX_DIGITS_REGEX = /^\d{6}$/; diff --git a/backend/ct_dashboard_api/src/email/password_reset.ts b/backend/ct_dashboard_api/src/email/password_reset.ts index 543911fd1..b30518921 100644 --- a/backend/ct_dashboard_api/src/email/password_reset.ts +++ b/backend/ct_dashboard_api/src/email/password_reset.ts @@ -12,7 +12,7 @@ export async function sendPasswordResetEmail( const subject = `Reset Password Verification Code for ${customer_label}`; const html = ` - Oko Email Template
Oko password reset code header

Enter this code in your Oko Dashboard to reset your password.
The code is valid for ${email_verification_expiration_minutes} minutes for your security.

 

Your 6-digit code
for changing your password

 

${verification_code}

 
 

If you didn't make this request, you can safely delete this email.

 

Oko Team

 
Gray Oko logo
+ Oko Email Template
Oko password reset code header

Enter this code in your Oko Dashboard to reset your password.
The code is valid for ${email_verification_expiration_minutes} minute for your security.

 

Your 6-digit code
for changing your password

 

${verification_code}

 
 

If you didn't make this request, you can safely delete this email.

 

Oko Team

 
Gray Oko logo
`; console.info( diff --git a/backend/ct_dashboard_api/src/routes/customer_auth.ts b/backend/ct_dashboard_api/src/routes/customer_auth.ts index d2a29a18c..4d67fe0e8 100644 --- a/backend/ct_dashboard_api/src/routes/customer_auth.ts +++ b/backend/ct_dashboard_api/src/routes/customer_auth.ts @@ -17,7 +17,10 @@ import { getCTDUserWithCustomerByEmail, } from "@oko-wallet/oko-pg-interface/customer_dashboard_users"; import { hashPassword, comparePassword } from "@oko-wallet/crypto-js"; -import { verifyEmailCode } from "@oko-wallet/oko-pg-interface/email_verifications"; +import { + verifyEmailCode, + markCodeVerified, +} from "@oko-wallet/oko-pg-interface/email_verifications"; import { registry } from "@oko-wallet/oko-api-openapi"; import { ErrorResponseSchema } from "@oko-wallet/oko-api-openapi/common"; import { @@ -41,6 +44,8 @@ import { generateCustomerToken } from "@oko-wallet-ctd-api/auth"; import { sendEmailVerificationCode } from "@oko-wallet-ctd-api/email/send"; import { CHANGED_PASSWORD_MIN_LENGTH, + CHANGED_PASSWORD_MAX_LENGTH, + PASSWORD_CONTAINS_NUMBER_REGEX, EMAIL_REGEX, SIX_DIGITS_REGEX, } from "@oko-wallet-ctd-api/constants"; @@ -51,10 +56,7 @@ import { import { rateLimitMiddleware } from "@oko-wallet-ctd-api/middleware/rate_limit"; import { generateVerificationCode } from "@oko-wallet-ctd-api/email/verification"; import { sendPasswordResetEmail } from "@oko-wallet-ctd-api/email/password_reset"; -import { - createEmailVerification, - getLatestPendingVerification, -} from "@oko-wallet/oko-pg-interface/email_verifications"; +import { createEmailVerification } from "@oko-wallet/oko-pg-interface/email_verifications"; export function setCustomerAuthRoutes(router: Router) { registry.registerPath({ @@ -291,16 +293,8 @@ export function setCustomerAuthRoutes(router: Router) { return; } - const pendingRes = await getLatestPendingVerification(state.db, email); - if (!pendingRes.success) { - res - .status(500) - .json({ success: false, code: "UNKNOWN_ERROR", msg: "DB Error" }); - return; - } - - const pending = pendingRes.data; - if (!pending || pending.verification_code !== code) { + const result = await markCodeVerified(state.db, email, code, 5); + if (!result.success) { res.status(400).json({ success: false, code: "INVALID_VERIFICATION_CODE", @@ -402,6 +396,24 @@ export function setCustomerAuthRoutes(router: Router) { return; } + if (newPassword.length > CHANGED_PASSWORD_MAX_LENGTH) { + res.status(400).json({ + success: false, + code: "INVALID_EMAIL_OR_PASSWORD", + msg: "Password too long", + }); + return; + } + + if (!PASSWORD_CONTAINS_NUMBER_REGEX.test(newPassword)) { + res.status(400).json({ + success: false, + code: "INVALID_EMAIL_OR_PASSWORD", + msg: "Password must include at least one number", + }); + return; + } + const verificationResult = await verifyEmailCode(state.db, { email, verification_code: code, @@ -1027,6 +1039,24 @@ export function setCustomerAuthRoutes(router: Router) { return; } + if (request.new_password.length > CHANGED_PASSWORD_MAX_LENGTH) { + res.status(400).json({ + success: false, + code: "INVALID_EMAIL_OR_PASSWORD", + msg: "Password must be at most 16 characters long", + }); + return; + } + + if (!PASSWORD_CONTAINS_NUMBER_REGEX.test(request.new_password)) { + res.status(400).json({ + success: false, + code: "INVALID_EMAIL_OR_PASSWORD", + msg: "Password must include at least one number", + }); + return; + } + // Inline changePassword logic const customerAccountResult = await getCTDUserWithCustomerAndPasswordHashByEmail( diff --git a/backend/oko_pg_interface/src/email_verifications/index.ts b/backend/oko_pg_interface/src/email_verifications/index.ts index ec9267b9e..dd5451ea7 100644 --- a/backend/oko_pg_interface/src/email_verifications/index.ts +++ b/backend/oko_pg_interface/src/email_verifications/index.ts @@ -15,11 +15,11 @@ export async function createEmailVerification( ): Promise> { const query = ` INSERT INTO email_verifications ( - email_verification_id, email, verification_code, + email_verification_id, email, verification_code, status, expires_at ) VALUES ( - $1, $2, $3, + $1, $2, $3, $4, $5 ) RETURNING * @@ -61,14 +61,14 @@ export async function verifyEmailCode( ): Promise> { try { const updateQuery = ` -UPDATE email_verifications +UPDATE email_verifications SET status = '${EmailVerificationStatus.VERIFIED}', updated_at = NOW() WHERE email_verification_id = ( SELECT email_verification_id FROM email_verifications WHERE email = $1 AND verification_code = $2 - AND status = '${EmailVerificationStatus.PENDING}' + AND status = '${EmailVerificationStatus.CODE_VERIFIED}' AND expires_at > NOW() ORDER BY created_at DESC LIMIT 1 @@ -110,14 +110,65 @@ RETURNING status } } +export async function markCodeVerified( + db: Pool, + email: string, + code: string, + extendMinutes: number = 5, +): Promise> { + const query = ` +UPDATE email_verifications +SET status = '${EmailVerificationStatus.CODE_VERIFIED}', + expires_at = NOW() + INTERVAL '1 minute' * $3, + updated_at = NOW() +WHERE email_verification_id = ( + SELECT email_verification_id + FROM email_verifications + WHERE email = $1 + AND verification_code = $2 + AND status = '${EmailVerificationStatus.PENDING}' + AND expires_at > NOW() + ORDER BY created_at DESC + LIMIT 1 +) +RETURNING * +`; + + try { + const result = await db.query(query, [ + email, + code, + extendMinutes, + ]); + + const row = result.rows[0]; + if (!row) { + return { + success: false, + err: "Invalid or expired verification code", + }; + } + + return { + success: true, + data: row, + }; + } catch (error) { + return { + success: false, + err: String(error), + }; + } +} + export async function getLatestPendingVerification( db: Pool, email: string, ): Promise> { const query = ` -SELECT * +SELECT * FROM email_verifications -WHERE email = $1 +WHERE email = $1 AND status = '${EmailVerificationStatus.PENDING}' AND expires_at > NOW() ORDER BY created_at DESC diff --git a/backend/openapi/src/ct_dashboard/customer_auth.ts b/backend/openapi/src/ct_dashboard/customer_auth.ts index b37458237..2c1698679 100644 --- a/backend/openapi/src/ct_dashboard/customer_auth.ts +++ b/backend/openapi/src/ct_dashboard/customer_auth.ts @@ -118,9 +118,15 @@ export const ChangePasswordRequestSchema = registry.register( email: z.email().openapi({ description: "Email address of the account", }), - new_password: z.string().min(8).openapi({ - description: "New password to set", - }), + new_password: z + .string() + .min(8) + .max(16) + .regex(/\d/, "Password must include at least one number") + .openapi({ + description: + "New password to set (8-16 characters, must include at least one number)", + }), original_password: z.string().optional().openapi({ description: "Current password for verification", }), @@ -219,9 +225,15 @@ export const ResetPasswordConfirmRequestSchema = registry.register( code: z.string().length(6).openapi({ description: "The 6-digit verification code", }), - newPassword: z.string().min(8).openapi({ - description: "The new password", - }), + newPassword: z + .string() + .min(8) + .max(16) + .regex(/\d/, "Password must include at least one number") + .openapi({ + description: + "The new password (8-16 characters, must include at least one number)", + }), }), ); diff --git a/common/oko_types/src/ct_dashboard/email_verification.ts b/common/oko_types/src/ct_dashboard/email_verification.ts index 2145516fa..84f657589 100644 --- a/common/oko_types/src/ct_dashboard/email_verification.ts +++ b/common/oko_types/src/ct_dashboard/email_verification.ts @@ -2,6 +2,7 @@ import type { SMTPConfig } from "../admin"; export enum EmailVerificationStatus { PENDING = "PENDING", + CODE_VERIFIED = "CODE_VERIFIED", VERIFIED = "VERIFIED", EXPIRED = "EXPIRED", } diff --git a/crypto/teddsa/teddsa_interface/tsconfig.json b/crypto/teddsa/teddsa_interface/tsconfig.json index 8d81c3fe1..e2b46401a 100644 --- a/crypto/teddsa/teddsa_interface/tsconfig.json +++ b/crypto/teddsa/teddsa_interface/tsconfig.json @@ -10,8 +10,8 @@ "declaration": true, "declarationMap": true, "outDir": "./dist", - "rootDir": "./src" + "rootDir": "./src", }, "include": ["src/**/*"], - "exclude": ["node_modules", "dist"] + "exclude": ["node_modules", "dist", "src/tests"], } diff --git a/ui/oko_common_ui/src/checkbox/checkbox.module.scss b/ui/oko_common_ui/src/checkbox/checkbox.module.scss index 9dd1f2903..7e3d8c821 100644 --- a/ui/oko_common_ui/src/checkbox/checkbox.module.scss +++ b/ui/oko_common_ui/src/checkbox/checkbox.module.scss @@ -16,17 +16,14 @@ align-items: center; } -[data-theme="light"] { - .checkboxInput { - color: var(--white); - } -} [data-theme="dark"] { .checkboxInput { color: var(--gray-700); } } + .checkboxInput { + color: var(--white); display: flex; justify-content: center; From 3497b8b585ad5b3a0b966b31203e5bc8c256fc95 Mon Sep 17 00:00:00 2001 From: Calvin Lee Date: Wed, 14 Jan 2026 17:16:13 +0900 Subject: [PATCH 5/5] project: add local CI setup and E2E tmux scripts --- scripts/README.md | 125 +++++++++++++++++++++++++++++++++++ scripts/ci-setup.sh | 136 ++++++++++++++++++++++++++++++++++++++ scripts/tmux-e2e-start.sh | 113 +++++++++++++++++++++++++++++++ scripts/tmux-e2e-stop.sh | 15 +++++ 4 files changed, 389 insertions(+) create mode 100644 scripts/README.md create mode 100755 scripts/ci-setup.sh create mode 100755 scripts/tmux-e2e-start.sh create mode 100755 scripts/tmux-e2e-stop.sh diff --git a/scripts/README.md b/scripts/README.md new file mode 100644 index 000000000..c24d55c53 --- /dev/null +++ b/scripts/README.md @@ -0,0 +1,125 @@ +# Scripts + +Shell scripts for local development environment setup and E2E testing. + +## Prerequisites + +- Node.js 22+ +- tmux +- Rust (optional, for cargo check) + +## Scripts + +### ci-setup.sh + +Sets up the local development environment by running the same build steps as GitHub CI. + +```bash +./scripts/ci-setup.sh [OPTIONS] +``` + +**Build Steps:** +1. Check Node.js version (22+) +2. Enable corepack +3. Install dependencies (`yarn install --immutable`) +4. Build CS packages (cait-sith WASM) +5. Build Frost packages (frost-ed25519 WASM) +6. Build internal packages +7. Build SDK packages +8. Run TypeScript typecheck +9. Run Rust cargo check + +**Options:** + +| Option | Description | +|--------|-------------| +| `--skip-rust` | Skip Rust cargo check | +| `--skip-typecheck` | Skip TypeScript typecheck | +| `-h, --help` | Show help message | + +**Examples:** + +```bash +# Full setup +./scripts/ci-setup.sh + +# Quick setup (skip checks) +./scripts/ci-setup.sh --skip-rust --skip-typecheck +``` + +--- + +### tmux-e2e-start.sh + +Starts all E2E services in a tmux session with separate windows. + +```bash +./scripts/tmux-e2e-start.sh [OPTIONS] +``` + +**Services Started:** + +| Window | Service | Command | +|--------|---------|---------| +| oko_api | Backend API | `yarn dev` | +| oko_attached | Embedded wallet | `yarn dev` | +| demo_web | Demo web app | `yarn dev` | +| ksn_1 | Key Share Node 1 | `yarn start` | +| ksn_2 | Key Share Node 2 | `yarn start_2` | +| ksn_3 | Key Share Node 3 | `yarn start_3` | + +**Options:** + +| Option | Description | +|--------|-------------| +| `--reset` | Reset database before starting (runs migrations and seed) | +| `-h, --help` | Show help message | + +**Database Reset Steps (when using `--reset`):** +1. `yarn ci db_migrate_api --use-env-file` +2. `yarn ci db_seed_api --use-env-file` +3. `yarn ci db_migrate_ksn --use-env-file` + +**Examples:** + +```bash +# Start services +./scripts/tmux-e2e-start.sh + +# Reset database and start +./scripts/tmux-e2e-start.sh --reset +``` + +--- + +### tmux-e2e-stop.sh + +Stops the E2E tmux session. + +```bash +./scripts/tmux-e2e-stop.sh +``` + +--- + +## Typical Workflow + +```bash +# 1. First time setup (run once) +./scripts/ci-setup.sh + +# 2. Start E2E environment with fresh database +./scripts/tmux-e2e-start.sh --reset + +# 3. When done, stop all services +./scripts/tmux-e2e-stop.sh +``` + +## Tmux Navigation + +Once attached to the session: +- `Ctrl+b n` - Next window +- `Ctrl+b p` - Previous window +- `Ctrl+b ` - Go to window by number (0-5) +- `Ctrl+b d` - Detach from session (services keep running) +- `Ctrl+b w` - List all windows diff --git a/scripts/ci-setup.sh b/scripts/ci-setup.sh new file mode 100755 index 000000000..e2fa6f7e6 --- /dev/null +++ b/scripts/ci-setup.sh @@ -0,0 +1,136 @@ +#!/bin/bash +set -e + +PROJECT_ROOT="$(cd "$(dirname "$0")/.." && pwd)" +cd "$PROJECT_ROOT" + +# Color definitions +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' + +print_info() { + echo -e "${GREEN}[INFO]${NC} $1" +} + +print_step() { + echo -e "${BLUE}[STEP]${NC} $1" +} + +print_warn() { + echo -e "${YELLOW}[WARN]${NC} $1" +} + +print_error() { + echo -e "${RED}[ERROR]${NC} $1" +} + +# Parse options +SKIP_RUST=false +SKIP_TYPECHECK=false + +while [[ $# -gt 0 ]]; do + case $1 in + --skip-rust) + SKIP_RUST=true + shift + ;; + --skip-typecheck) + SKIP_TYPECHECK=true + shift + ;; + -h|--help) + echo "Usage: $0 [OPTIONS]" + echo "" + echo "Local CI setup script - prepares the development environment" + echo "" + echo "Options:" + echo " --skip-rust Skip Rust cargo check" + echo " --skip-typecheck Skip TypeScript typecheck" + echo " -h, --help Show this help message" + exit 0 + ;; + *) + print_error "Unknown option: $1" + echo "Use -h or --help for usage information" + exit 1 + ;; + esac +done + +echo "" +echo "==========================================" +echo " Oko Local CI Setup" +echo "==========================================" +echo "" + +# Check Node.js version +print_step "Checking Node.js version..." +NODE_VERSION=$(node -v | cut -d'v' -f2 | cut -d'.' -f1) +if [ "$NODE_VERSION" -lt 22 ]; then + print_error "Node.js 22+ required. Current: $(node -v)" + exit 1 +fi +print_info "Node.js $(node -v) OK" + +# Enable corepack +print_step "Enabling corepack..." +corepack enable +print_info "Corepack enabled" + +# Install dependencies +print_step "Installing dependencies..." +yarn install --immutable +print_info "Dependencies installed" + +# Build CS packages (WASM) +print_step "Building CS packages (cait-sith WASM)..." +yarn ci build_cs +print_info "CS packages built" + +# Build Frost packages (EdDSA WASM) +print_step "Building Frost packages (frost-ed25519 WASM)..." +yarn ci build_frost +print_info "Frost packages built" + +# Build internal packages +print_step "Building internal packages..." +yarn ci build_pkgs +print_info "Internal packages built" + +# Build SDK packages +print_step "Building SDK packages..." +yarn ci build_sdk +print_info "SDK packages built" + +# TypeScript typecheck +if [ "$SKIP_TYPECHECK" = false ]; then + print_step "Running TypeScript typecheck..." + yarn ci typecheck + print_info "Typecheck passed" +else + print_warn "Skipping TypeScript typecheck" +fi + +# Rust check +if [ "$SKIP_RUST" = false ]; then + if command -v cargo &> /dev/null; then + print_step "Running Rust cargo check..." + cargo check --workspace + print_info "Rust check passed" + else + print_warn "Rust not installed, skipping cargo check" + fi +else + print_warn "Skipping Rust cargo check" +fi + +echo "" +echo "==========================================" +echo -e " ${GREEN}Setup Complete!${NC}" +echo "==========================================" +echo "" +print_info "You can now run: ./scripts/tmux-e2e-start.sh" +echo "" diff --git a/scripts/tmux-e2e-start.sh b/scripts/tmux-e2e-start.sh new file mode 100755 index 000000000..01126ddfb --- /dev/null +++ b/scripts/tmux-e2e-start.sh @@ -0,0 +1,113 @@ +#!/bin/bash +set -e + +SESSION_NAME="oko-e2e" +PROJECT_ROOT="$(cd "$(dirname "$0")/.." && pwd)" +RESET_DB=false + +# Color definitions +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' + +print_info() { + echo -e "${GREEN}[INFO]${NC} $1" +} + +print_warn() { + echo -e "${YELLOW}[WARN]${NC} $1" +} + +print_error() { + echo -e "${RED}[ERROR]${NC} $1" +} + +# Parse options +while [[ $# -gt 0 ]]; do + case $1 in + --reset) + RESET_DB=true + shift + ;; + -h|--help) + echo "Usage: $0 [OPTIONS]" + echo "" + echo "Options:" + echo " --reset Reset database before starting services" + echo " -h, --help Show this help message" + exit 0 + ;; + *) + print_error "Unknown option: $1" + echo "Use -h or --help for usage information" + exit 1 + ;; + esac +done + +# Check tmux installation +if ! command -v tmux &> /dev/null; then + print_error "tmux is not installed. Please install tmux first." + exit 1 +fi + +# Check and kill existing session +if tmux has-session -t "$SESSION_NAME" 2>/dev/null; then + print_warn "Existing session '$SESSION_NAME' found. Killing it..." + tmux kill-session -t "$SESSION_NAME" +fi + +# Reset database +if [ "$RESET_DB" = true ]; then + print_info "Resetting database..." + cd "$PROJECT_ROOT" + + print_info "Running: yarn ci db_migrate_api --use-env-file" + yarn ci db_migrate_api --use-env-file + + print_info "Running: yarn ci db_seed_api --use-env-file" + yarn ci db_seed_api --use-env-file + + print_info "Running: yarn ci db_migrate_ksn --use-env-file" + yarn ci db_migrate_ksn --use-env-file + + print_info "Database reset complete!" +fi + +print_info "Creating tmux session: $SESSION_NAME" + +# 1. oko_api (create session with first window) +tmux new-session -d -s "$SESSION_NAME" -n "oko_api" -c "$PROJECT_ROOT/backend/oko_api/server" +tmux send-keys -t "$SESSION_NAME:oko_api" "yarn dev" C-m + +# 2. oko_attached +tmux new-window -t "$SESSION_NAME" -n "oko_attached" -c "$PROJECT_ROOT/embed/oko_attached" +tmux send-keys -t "$SESSION_NAME:oko_attached" "yarn dev" C-m + +# 3. demo_web +tmux new-window -t "$SESSION_NAME" -n "demo_web" -c "$PROJECT_ROOT/apps/demo_web" +tmux send-keys -t "$SESSION_NAME:demo_web" "yarn dev" C-m + +# 4. ksn_1 +tmux new-window -t "$SESSION_NAME" -n "ksn_1" -c "$PROJECT_ROOT/key_share_node/server" +tmux send-keys -t "$SESSION_NAME:ksn_1" "yarn start" C-m + +# 5. ksn_2 +tmux new-window -t "$SESSION_NAME" -n "ksn_2" -c "$PROJECT_ROOT/key_share_node/server" +tmux send-keys -t "$SESSION_NAME:ksn_2" "yarn start_2" C-m + +# 6. ksn_3 +tmux new-window -t "$SESSION_NAME" -n "ksn_3" -c "$PROJECT_ROOT/key_share_node/server" +tmux send-keys -t "$SESSION_NAME:ksn_3" "yarn start_3" C-m + +# Select first window +tmux select-window -t "$SESSION_NAME:oko_api" + +print_info "All services started in tmux session: $SESSION_NAME" +print_info "Windows: oko_api, oko_attached, demo_web, ksn_1, ksn_2, ksn_3" +echo "" +print_info "Attaching to session..." + +# Attach to session +tmux attach-session -t "$SESSION_NAME" diff --git a/scripts/tmux-e2e-stop.sh b/scripts/tmux-e2e-stop.sh new file mode 100755 index 000000000..1bb61f87f --- /dev/null +++ b/scripts/tmux-e2e-stop.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +SESSION_NAME="oko-e2e" + +# Color definitions +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' + +if tmux has-session -t "$SESSION_NAME" 2>/dev/null; then + tmux kill-session -t "$SESSION_NAME" + echo -e "${GREEN}[INFO]${NC} Session '$SESSION_NAME' terminated." +else + echo -e "${YELLOW}[WARN]${NC} Session '$SESSION_NAME' not found." +fi