-
Notifications
You must be signed in to change notification settings - Fork 54
chore: apply prettier formatting #135
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
cybermax4200
wants to merge
9
commits into
ancore-org:main
Choose a base branch
from
cybermax4200:feat/crypto-utilities-package
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 8 commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
10e733b
chore: apply prettier formatting
cybermax4200 440473f
Merge branch 'main' into feat/crypto-utilities-package
cybermax4200 f3da68a
Merge branch 'main' into feat/crypto-utilities-package
cybermax4200 ba14c90
fix(crypto): address CodeRabbit review feedback
cybermax4200 d9f3b3e
fix(types): disable composite mode to fix tsup DTS build
cybermax4200 e6f7744
fix(crypto): add DOM lib and composite:false to tsconfig for DTS build
cybermax4200 fda3875
fix: remove composite/rootDir from tsconfigs to fix DTS builds across…
cybermax4200 4c42255
Merge branch 'main' into feat/crypto-utilities-package
cybermax4200 43717a2
fix(crypto): remove Buffer usage and add node globals to eslint config
cybermax4200 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| {"specId": "f09d6234-a0e2-4cd6-897c-ffb58e9d1e76", "workflowType": "requirements-first", "specType": "feature"} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,261 @@ | ||
| # Design Document: @ancore/crypto Package Integration | ||
|
|
||
| ## Overview | ||
|
|
||
| The `@ancore/crypto` package is the single cryptographic entry point for the Ancore wallet monorepo. Currently it is a stub that exports only `CRYPTO_VERSION` and `verifySignature`. This design covers wiring the package together: updating `packages/crypto/src/index.ts` to re-export all public symbols from every submodule, and adding a smoke test that verifies the export surface is complete and correct. | ||
|
|
||
| The scope is **integration and export correctness only**. The internal logic of each submodule (`signing.ts`, `hashing.ts`, `keys.ts`, etc.) is implemented in separate issues (#065–#072). This design assumes those submodules will exist on disk when the index is updated. | ||
|
|
||
| Key design goals: | ||
|
|
||
| - One import path (`@ancore/crypto`) for all consumers — no internal path leakage. | ||
| - Clean TypeScript build producing CJS, ESM, and `.d.ts` outputs via `tsup`. | ||
| - A smoke test that acts as a living manifest of the public API surface. | ||
| - Zero secret material in logs or error messages. | ||
|
|
||
| --- | ||
|
|
||
| ## Architecture | ||
|
|
||
| The package follows a **barrel export** pattern. Each submodule owns its domain and explicitly marks its public surface with named exports. The index file is a pure re-export aggregator — it contains no logic of its own. | ||
|
|
||
| ```mermaid | ||
| graph TD | ||
| Consumer["Consumer\n(@ancore/core-sdk, apps, etc.)"] | ||
| Index["index.ts\n(barrel — re-exports only)"] | ||
| Signing["signing.ts\n(verifySignature, signMessage)"] | ||
| Hashing["hashing.ts\n(sha256, sha512, hmac)"] | ||
| Keys["keys.ts\n(deriveKeyPair, publicKeyFromSecret)"] | ||
| Mnemonic["mnemonic.ts\n(generateMnemonic, mnemonicToSeed)"] | ||
| Encoding["encoding.ts\n(toHex, fromHex, toBase64, fromBase64)"] | ||
|
|
||
| Consumer -->|"import { ... } from '@ancore/crypto'"| Index | ||
| Index --> Signing | ||
| Index --> Hashing | ||
| Index --> Keys | ||
| Index --> Mnemonic | ||
| Index --> Encoding | ||
| ``` | ||
|
|
||
| Build pipeline: | ||
|
|
||
| ```mermaid | ||
| graph LR | ||
| TS["TypeScript sources\n(src/*.ts)"] | ||
| tsup["tsup"] | ||
| CJS["dist/index.js\n(CommonJS)"] | ||
| ESM["dist/index.mjs\n(ESM)"] | ||
| DTS["dist/index.d.ts\n(declarations)"] | ||
|
|
||
| TS --> tsup --> CJS | ||
| tsup --> ESM | ||
| tsup --> DTS | ||
| ``` | ||
|
|
||
| --- | ||
|
|
||
| ## Components and Interfaces | ||
|
|
||
| ### index.ts — Barrel Export | ||
|
|
||
| The index is the only file consumers interact with. Its structure is: | ||
|
|
||
| ```typescript | ||
| export const CRYPTO_VERSION = '0.1.0'; | ||
|
|
||
| export * from './signing'; | ||
| export * from './hashing'; | ||
| export * from './keys'; | ||
| export * from './mnemonic'; | ||
| export * from './encoding'; | ||
| ``` | ||
|
|
||
| Rules: | ||
|
|
||
| - Only `export *` or named `export { ... }` from submodules — no logic. | ||
| - If a submodule has name collisions, use explicit named re-exports with aliases. | ||
| - Internal helpers (e.g., `toMessageBytes`, `isHex`) must **not** be exported from their submodule's public surface. | ||
|
|
||
| ### Submodule Contract | ||
|
|
||
| Each submodule must follow this contract so the barrel works correctly: | ||
|
|
||
| | Rule | Detail | | ||
| | ---------------------------- | --------------------------------------------------------------- | | ||
| | Named exports only | No default exports — enables `export *` without ambiguity | | ||
| | No console calls | `console.log/warn/error` are forbidden in production code paths | | ||
| | No secret material in errors | Error messages must not include key bytes, seeds, or mnemonics | | ||
| | Pure functions preferred | Side-effect-free functions are easier to test and tree-shake | | ||
|
|
||
| ### Expected Submodules and Their Public Symbols | ||
|
|
||
| The table below defines the intended public API surface. It will be updated as issues #065–#072 land. | ||
|
|
||
| | Submodule | Public Exports | | ||
| | ------------- | -------------------------------------------- | | ||
| | `signing.ts` | `verifySignature`, `signMessage` | | ||
| | `hashing.ts` | `sha256`, `sha512`, `hmac` | | ||
| | `keys.ts` | `deriveKeyPair`, `publicKeyFromSecret` | | ||
| | `mnemonic.ts` | `generateMnemonic`, `mnemonicToSeed` | | ||
| | `encoding.ts` | `toHex`, `fromHex`, `toBase64`, `fromBase64` | | ||
| | `index.ts` | `CRYPTO_VERSION` + all of the above | | ||
|
|
||
| ### Smoke Test — `__tests__/smoke.test.ts` | ||
|
|
||
| The smoke test is a living manifest of the public API. It: | ||
|
|
||
| 1. Imports the entire namespace from `@ancore/crypto`. | ||
| 2. Asserts every expected symbol is defined. | ||
| 3. Invokes at least one async function with valid inputs. | ||
| 4. Spies on `console` methods to assert no output occurs. | ||
|
|
||
| ```typescript | ||
| import * as CryptoAPI from '@ancore/crypto'; | ||
|
|
||
| const EXPECTED_EXPORTS = [ | ||
| 'CRYPTO_VERSION', | ||
| 'verifySignature', | ||
| 'signMessage', | ||
| 'sha256', | ||
| 'sha512', | ||
| 'hmac', | ||
| 'deriveKeyPair', | ||
| 'publicKeyFromSecret', | ||
| 'generateMnemonic', | ||
| 'mnemonicToSeed', | ||
| 'toHex', | ||
| 'fromHex', | ||
| 'toBase64', | ||
| 'fromBase64', | ||
| ] as const; | ||
| ``` | ||
|
|
||
| --- | ||
|
|
||
| ## Data Models | ||
|
|
||
| This package is a utility library — it has no persistent state or database models. The relevant data types are: | ||
|
|
||
| ```typescript | ||
| // Shared input type for signable values | ||
| type SignableValue = string | Uint8Array; | ||
|
|
||
| // Key pair returned by key derivation | ||
| interface KeyPair { | ||
| publicKey: string; // Stellar-encoded G... address | ||
| secretKey: string; // Stellar-encoded S... secret | ||
| } | ||
|
|
||
| // Result of mnemonic-to-seed derivation | ||
| interface SeedResult { | ||
| seed: Uint8Array; // 64-byte BIP39 seed | ||
| mnemonic: string; // space-separated word list | ||
| } | ||
| ``` | ||
|
|
||
| These types are defined in their respective submodules and re-exported through the index. They may also be shared with `@ancore/types` if needed by other packages. | ||
|
|
||
| --- | ||
|
|
||
| ## Correctness Properties | ||
|
|
||
| _A property is a characteristic or behavior that should hold true across all valid executions of a system — essentially, a formal statement about what the system should do. Properties serve as the bridge between human-readable specifications and machine-verifiable correctness guarantees._ | ||
|
|
||
| ### Property 1: All expected exports are defined | ||
|
|
||
| _For any_ symbol in the declared public API list, importing that symbol from `@ancore/crypto` should yield a value that is not `undefined`. | ||
|
|
||
| **Validates: Requirements 1.1, 1.3, 3.1, 5.2** | ||
|
|
||
| ### Property 2: Export set matches the public API exactly | ||
|
|
||
| _For any_ key present in the module namespace imported from `@ancore/crypto`, that key should appear in the declared public API list — and conversely, every key in the declared list should appear in the namespace. The sets are equal. | ||
|
|
||
| **Validates: Requirements 1.4, 4.3** | ||
|
|
||
| ### Property 3: No console output during normal operation | ||
|
|
||
| _For any_ call to an exported function with valid inputs, the `console.log`, `console.warn`, and `console.error` methods should not be invoked. | ||
|
|
||
| **Validates: Requirements 3.3, 4.1** | ||
|
|
||
| ### Property 4: Error messages do not contain secret material | ||
|
|
||
| _For any_ exported function called with an invalid input alongside a known secret value (e.g., a random 32-byte seed), any error thrown or rejection returned should not include the secret value in its message string. | ||
|
|
||
| **Validates: Requirements 4.2** | ||
|
|
||
| ### Property 5: Module resolution is idempotent | ||
|
|
||
| _For any_ named export from `@ancore/crypto`, importing the same symbol twice (in the same process) should yield the same reference (`===` equality), confirming stable module identity. | ||
|
|
||
| **Validates: Requirements 5.3** | ||
|
|
||
| --- | ||
|
|
||
| ## Error Handling | ||
|
|
||
| | Scenario | Behavior | | ||
| | ---------------------------------------------- | ------------------------------------------------------------------------------------------ | | ||
| | Invalid public key passed to `verifySignature` | Returns `false` (already implemented) — never throws | | ||
| | Malformed hex/base64 in encoding functions | Throws a `TypeError` with a message describing the format issue, not the input value | | ||
| | Invalid mnemonic passed to `mnemonicToSeed` | Throws a typed `CryptoError` with a safe message | | ||
| | Missing submodule at build time | `tsup` / `tsc` fails with a module-not-found error identifying the missing file | | ||
| | Secret material in error path | Forbidden — error messages must use placeholders like `"invalid key"`, never the key bytes | | ||
|
|
||
| A `CryptoError` class (or discriminated union) may be introduced in a future issue to give consumers typed error handling. For now, functions either return a safe value (like `false`) or throw a plain `Error` with a safe message. | ||
|
|
||
| --- | ||
|
|
||
| ## Testing Strategy | ||
|
|
||
| ### Dual Approach | ||
|
|
||
| Both unit tests and property-based tests are used. They are complementary: | ||
|
|
||
| - **Unit tests** cover specific examples, integration points, and known edge cases. | ||
| - **Property tests** verify universal invariants across randomly generated inputs. | ||
|
|
||
| ### Unit Tests | ||
|
|
||
| Located in `packages/crypto/src/__tests__/`. Existing tests (`verify-signature.test.ts`) remain unchanged. New file: `smoke.test.ts`. | ||
|
|
||
| Unit test focus areas: | ||
|
|
||
| - Specific valid/invalid input examples for each exported function. | ||
| - Edge cases: empty strings, zero-length buffers, all-zero keys. | ||
| - Error path assertions: confirm safe error messages. | ||
|
|
||
| ### Property-Based Tests | ||
|
|
||
| Library: **`fast-check`** (TypeScript-native, works with Jest via `fc.assert`). | ||
|
|
||
| Install: `pnpm add -D fast-check --filter @ancore/crypto` | ||
|
|
||
| Configuration: each property test runs a minimum of **100 iterations**. | ||
|
|
||
| Each test is tagged with a comment referencing the design property: | ||
|
|
||
| ```typescript | ||
| // Feature: crypto-utilities-package, Property 1: All expected exports are defined | ||
| fc.assert( | ||
| fc.property(fc.constantFrom(...EXPECTED_EXPORTS), (symbol) => { | ||
| expect(CryptoAPI[symbol]).toBeDefined(); | ||
| }), | ||
| { numRuns: 100 } | ||
| ); | ||
| ``` | ||
|
|
||
| ### Property Test Mapping | ||
|
|
||
| | Design Property | Test Description | Pattern | | ||
| | --------------- | ------------------------------------------------------------------- | ------------------------ | | ||
| | Property 1 | For each symbol in EXPECTED_EXPORTS, it is defined in the namespace | Invariant | | ||
| | Property 2 | Namespace keys === EXPECTED_EXPORTS (no extras, no missing) | Invariant | | ||
| | Property 3 | No console calls during valid function invocations | Invariant | | ||
| | Property 4 | Error messages from invalid inputs don't contain the secret value | Error condition | | ||
| | Property 5 | Same symbol imported twice yields `===` reference | Idempotence / Round-trip | | ||
|
|
||
| ### CI Integration | ||
|
|
||
| The existing `jest` setup in `jest.config.cjs` picks up all `*.test.ts` files under `src/__tests__/`. No additional infrastructure is needed — `fast-check` integrates directly with Jest's `it`/`test` blocks. | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,81 @@ | ||
| # Requirements Document | ||
|
|
||
| ## Introduction | ||
|
|
||
| The `@ancore/crypto` package provides cryptographic utilities for the Ancore wallet. Currently the package is a stub — only `CRYPTO_VERSION` and `verifySignature` are exported. This feature wires together all cryptographic submodules (signing, hashing, key derivation, etc., implemented in separate issues #065–#072) and exposes a clean, stable public API surface from `packages/crypto/src/index.ts`. The scope here is integration and export correctness, not the internal logic of each submodule. | ||
|
|
||
| ## Glossary | ||
|
|
||
| - **Package**: The `@ancore/crypto` npm package located at `packages/crypto`. | ||
| - **Index**: The file `packages/crypto/src/index.ts` — the single public entry point of the Package. | ||
| - **Submodule**: A TypeScript source file inside `packages/crypto/src/` that implements a cohesive group of cryptographic functions (e.g., `signing.ts`, `hashing.ts`, `keys.ts`). | ||
| - **Public_API**: The set of functions, types, and constants re-exported from the Index. | ||
| - **Consumer**: Any package or application that imports from `@ancore/crypto`. | ||
| - **Secret_Material**: Private keys, seed phrases, raw entropy, or any value that must not be logged or exposed outside its intended scope. | ||
| - **Smoke_Test**: A lightweight test that imports from the Index and asserts that exported symbols are callable and return expected types, without exercising full cryptographic correctness. | ||
| - **Build**: The TypeScript compilation and bundling step executed via `tsup`. | ||
|
|
||
| --- | ||
|
|
||
| ## Requirements | ||
|
|
||
| ### Requirement 1: Public API Surface | ||
|
|
||
| **User Story:** As a Consumer, I want all cryptographic utilities to be importable from `@ancore/crypto`, so that I do not need to reference internal submodule paths. | ||
|
|
||
| #### Acceptance Criteria | ||
|
|
||
| 1. THE Index SHALL re-export every public function and type from each Submodule present in `packages/crypto/src/`. | ||
| 2. THE Index SHALL export `CRYPTO_VERSION` as a string constant. | ||
| 3. WHEN a Consumer imports a symbol from `@ancore/crypto`, THE Package SHALL resolve that symbol without requiring the Consumer to reference any internal Submodule path. | ||
| 4. THE Index SHALL NOT export any symbol that is not part of the intended Public_API (i.e., internal helpers remain unexported). | ||
|
|
||
| --- | ||
|
|
||
| ### Requirement 2: Build Integrity | ||
|
|
||
| **User Story:** As a developer, I want the package to compile cleanly, so that downstream packages can depend on `@ancore/crypto` without build failures. | ||
|
|
||
| #### Acceptance Criteria | ||
|
|
||
| 1. WHEN the Build is executed, THE Package SHALL produce no TypeScript compiler errors. | ||
| 2. WHEN the Build is executed, THE Package SHALL produce no missing-import or missing-export errors. | ||
| 3. THE Package SHALL generate CommonJS (`dist/index.js`), ESM (`dist/index.mjs`), and TypeScript declaration (`dist/index.d.ts`) outputs. | ||
| 4. IF a Submodule referenced in the Index does not exist on disk, THEN THE Build SHALL fail with a descriptive error identifying the missing Submodule. | ||
|
|
||
| --- | ||
|
|
||
| ### Requirement 3: Smoke Test | ||
|
|
||
| **User Story:** As a developer, I want a smoke test that verifies the wiring of exports, so that integration regressions are caught immediately. | ||
|
|
||
| #### Acceptance Criteria | ||
|
|
||
| 1. THE Smoke_Test SHALL import each symbol exported from the Index and assert that the symbol is defined (not `undefined`). | ||
| 2. THE Smoke_Test SHALL invoke at least one exported async function with valid inputs and assert that it resolves without throwing. | ||
| 3. WHEN the Smoke_Test is executed, THE Package SHALL not log any output to `console.log`, `console.warn`, or `console.error`. | ||
| 4. THE Smoke_Test SHALL pass within the existing Jest test suite without requiring additional test infrastructure. | ||
|
|
||
| --- | ||
|
|
||
| ### Requirement 4: No Secret Material Exposure | ||
|
|
||
| **User Story:** As a security reviewer, I want the package to never log or expose Secret Material, so that private keys and seeds cannot be leaked through observability tooling. | ||
|
|
||
| #### Acceptance Criteria | ||
|
|
||
| 1. THE Package SHALL NOT call `console.log`, `console.warn`, `console.error`, or any equivalent logging function with Secret_Material as an argument. | ||
| 2. IF an error occurs during a cryptographic operation, THEN THE Package SHALL return an error result or throw a typed error WITHOUT including Secret_Material in the error message. | ||
| 3. THE Index SHALL NOT re-export any internal utility whose sole purpose is to handle or transform raw Secret_Material in an unprotected form. | ||
|
|
||
| --- | ||
|
|
||
| ### Requirement 5: Export Completeness Verification | ||
|
|
||
| **User Story:** As a developer, I want a way to verify that all intended exports are present after submodules are added, so that accidental omissions are caught during CI. | ||
|
|
||
| #### Acceptance Criteria | ||
|
|
||
| 1. WHEN a new Submodule is added to `packages/crypto/src/`, THE Index SHALL be updated to include a re-export of that Submodule's public symbols. | ||
| 2. THE Smoke_Test SHALL enumerate and assert the presence of each named export defined in the Public_API, so that a missing re-export causes a test failure. | ||
| 3. FOR ALL symbols asserted in the Smoke_Test, importing then re-importing the same symbol from `@ancore/crypto` SHALL resolve to the same reference (idempotent module resolution). |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
Repository: ancore-org/ancore
Length of output: 176
🏁 Script executed:
Repository: ancore-org/ancore
Length of output: 173
Design specifies
signMessagebut implementation exportssignTransaction.Line 96 in the Expected Submodules table lists
signMessageas a public export fromsigning.ts, but the actual implementation exportssignTransactioninstead. This discrepancy should be reconciled — either:signing.tsto exportsignMessage(or both)signTransaction🤖 Prompt for AI Agents