feat: Add implementation details and dependencies
- Added a detailed implementation status report (impl.md). - Added the `@noble/hashes` dependency for Blake3 hashing. - Updated package.json and pnpm-lock.yaml accordingly. - Created a new component for Blake3 hashing demo.
This commit is contained in:
@@ -31,6 +31,7 @@
|
||||
"@libp2p/webrtc": "^5.2.12",
|
||||
"@libp2p/websockets": "^9.2.10",
|
||||
"@libp2p/webtransport": "^5.0.40",
|
||||
"@noble/hashes": "^1.8.0",
|
||||
"@tailwindcss/postcss": "^4.1.6",
|
||||
"@tailwindcss/vite": "^4.1.6",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
|
4919
sweb/pnpm-lock.yaml
generated
4919
sweb/pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
198
sweb/src/components/BlakeHashDemo.svelte
Normal file
198
sweb/src/components/BlakeHashDemo.svelte
Normal file
@@ -0,0 +1,198 @@
|
||||
<script lang="ts">
|
||||
import { cryptoService } from '../services/crypto.service';
|
||||
import { contentProcessorService } from '../services/content-processor.service';
|
||||
import { ipfsService } from '../services/ipfs.service';
|
||||
import { onMount } from 'svelte';
|
||||
|
||||
let textInput = '';
|
||||
let blakeHash = '';
|
||||
let selectedFile: File | null = null;
|
||||
let fileBlakeHash = '';
|
||||
let normalizedFilename = '';
|
||||
let ipfsCid = '';
|
||||
let combinedKey = '';
|
||||
let isProcessing = false;
|
||||
let errorMessage = '';
|
||||
let successMessage = '';
|
||||
|
||||
// Hash the text input using Blake3
|
||||
function hashText() {
|
||||
try {
|
||||
errorMessage = '';
|
||||
if (!textInput.trim()) {
|
||||
errorMessage = 'Please enter some text to hash';
|
||||
return;
|
||||
}
|
||||
blakeHash = cryptoService.hashStringBlake3AsHex(textInput);
|
||||
successMessage = 'Text hashed successfully!';
|
||||
} catch (error) {
|
||||
console.error('Error hashing text:', error);
|
||||
errorMessage = `Error hashing text: ${error instanceof Error ? error.message : String(error)}`;
|
||||
}
|
||||
}
|
||||
|
||||
// Handle file selection
|
||||
function handleFileSelect(event: Event) {
|
||||
const input = event.target as HTMLInputElement;
|
||||
if (input.files && input.files.length > 0) {
|
||||
selectedFile = input.files[0];
|
||||
// Reset previous results
|
||||
fileBlakeHash = '';
|
||||
normalizedFilename = '';
|
||||
ipfsCid = '';
|
||||
combinedKey = '';
|
||||
errorMessage = '';
|
||||
successMessage = '';
|
||||
}
|
||||
}
|
||||
|
||||
// Process the selected file
|
||||
async function processFile() {
|
||||
if (!selectedFile) {
|
||||
errorMessage = 'Please select a file to process';
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
isProcessing = true;
|
||||
errorMessage = '';
|
||||
successMessage = '';
|
||||
|
||||
// Normalize the filename
|
||||
normalizedFilename = contentProcessorService.normalizeFilename(selectedFile.name);
|
||||
|
||||
// Hash the file using Blake3
|
||||
fileBlakeHash = await cryptoService.hashFileBlake3AsHex(selectedFile);
|
||||
|
||||
// Process the file through the content processing pipeline
|
||||
const metadata = await contentProcessorService.processFile(selectedFile);
|
||||
|
||||
// Update the UI with the results
|
||||
ipfsCid = metadata.ipfsCid;
|
||||
combinedKey = metadata.combinedKey;
|
||||
|
||||
isProcessing = false;
|
||||
successMessage = 'File processed successfully!';
|
||||
} catch (error) {
|
||||
console.error('Error processing file:', error);
|
||||
errorMessage = `Error processing file: ${error instanceof Error ? error.message : String(error)}`;
|
||||
isProcessing = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize IPFS when the component mounts
|
||||
onMount(async () => {
|
||||
try {
|
||||
await ipfsService.initialize();
|
||||
} catch (error) {
|
||||
console.error('Error initializing IPFS:', error);
|
||||
errorMessage = `Error initializing IPFS: ${error instanceof Error ? error.message : String(error)}`;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<div class="p-6 max-w-4xl mx-auto bg-white rounded-lg shadow-md">
|
||||
<h2 class="text-2xl font-bold mb-6">Blake Hashing Demo</h2>
|
||||
|
||||
<!-- Text Input Section -->
|
||||
<div class="mb-8 p-4 border border-gray-200 rounded-md">
|
||||
<h3 class="text-xl font-semibold mb-4">Text Hashing</h3>
|
||||
<div class="mb-4">
|
||||
<label for="textInput" class="block text-sm font-medium text-gray-700 mb-1">Enter text to hash:</label>
|
||||
<textarea
|
||||
id="textInput"
|
||||
bind:value={textInput}
|
||||
class="w-full p-2 border border-gray-300 rounded-md focus:ring-blue-500 focus:border-blue-500"
|
||||
rows="3"
|
||||
></textarea>
|
||||
</div>
|
||||
<button
|
||||
on:click={hashText}
|
||||
class="px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2"
|
||||
>
|
||||
Hash Text
|
||||
</button>
|
||||
{#if blakeHash}
|
||||
<div class="mt-4">
|
||||
<h4 class="text-sm font-medium text-gray-700 mb-1">Blake3 Hash:</h4>
|
||||
<div class="p-2 bg-gray-100 rounded-md overflow-x-auto">
|
||||
<code class="text-sm break-all">{blakeHash}</code>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<!-- File Processing Section -->
|
||||
<div class="p-4 border border-gray-200 rounded-md">
|
||||
<h3 class="text-xl font-semibold mb-4">File Processing</h3>
|
||||
<div class="mb-4">
|
||||
<label for="fileInput" class="block text-sm font-medium text-gray-700 mb-1">Select a file to process:</label>
|
||||
<input
|
||||
type="file"
|
||||
id="fileInput"
|
||||
on:change={handleFileSelect}
|
||||
class="block w-full text-sm text-gray-500 file:mr-4 file:py-2 file:px-4 file:rounded-md file:border-0 file:text-sm file:font-semibold file:bg-blue-50 file:text-blue-700 hover:file:bg-blue-100"
|
||||
/>
|
||||
</div>
|
||||
<button
|
||||
on:click={processFile}
|
||||
disabled={!selectedFile || isProcessing}
|
||||
class="px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 disabled:bg-blue-300 disabled:cursor-not-allowed"
|
||||
>
|
||||
{isProcessing ? 'Processing...' : 'Process File'}
|
||||
</button>
|
||||
|
||||
{#if selectedFile && (normalizedFilename || fileBlakeHash || ipfsCid || combinedKey)}
|
||||
<div class="mt-4 space-y-3">
|
||||
{#if normalizedFilename}
|
||||
<div>
|
||||
<h4 class="text-sm font-medium text-gray-700 mb-1">Normalized Filename:</h4>
|
||||
<div class="p-2 bg-gray-100 rounded-md overflow-x-auto">
|
||||
<code class="text-sm break-all">{normalizedFilename}</code>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#if fileBlakeHash}
|
||||
<div>
|
||||
<h4 class="text-sm font-medium text-gray-700 mb-1">Blake3 Hash:</h4>
|
||||
<div class="p-2 bg-gray-100 rounded-md overflow-x-auto">
|
||||
<code class="text-sm break-all">{fileBlakeHash}</code>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#if ipfsCid}
|
||||
<div>
|
||||
<h4 class="text-sm font-medium text-gray-700 mb-1">IPFS CID:</h4>
|
||||
<div class="p-2 bg-gray-100 rounded-md overflow-x-auto">
|
||||
<code class="text-sm break-all">{ipfsCid}</code>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#if combinedKey}
|
||||
<div>
|
||||
<h4 class="text-sm font-medium text-gray-700 mb-1">Combined Key (Blake Hash + IPFS CID):</h4>
|
||||
<div class="p-2 bg-gray-100 rounded-md overflow-x-auto">
|
||||
<code class="text-sm break-all">{combinedKey}</code>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<!-- Messages -->
|
||||
{#if errorMessage}
|
||||
<div class="mt-4 p-3 bg-red-100 text-red-700 rounded-md">
|
||||
{errorMessage}
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#if successMessage}
|
||||
<div class="mt-4 p-3 bg-green-100 text-green-700 rounded-md">
|
||||
{successMessage}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
@@ -1,15 +1,10 @@
|
||||
<script lang="ts">
|
||||
import MarkdownContent from "./MarkdownContent.svelte";
|
||||
import IPFSDemo from "./IPFSDemo.svelte";
|
||||
import Button from "$lib/components/ui/button/button.svelte";
|
||||
|
||||
export let contentPath: string = "introduction/introduction";
|
||||
|
||||
// Default to introduction if no path is provided
|
||||
$: actualPath = contentPath || "introduction/introduction";
|
||||
|
||||
// Flag to show IPFS demo
|
||||
let showIPFSDemo = false;
|
||||
</script>
|
||||
|
||||
<div class="">
|
||||
@@ -20,35 +15,17 @@
|
||||
<MarkdownContent path={actualPath} />
|
||||
</div>
|
||||
{:else}
|
||||
<!-- IPFS Demo Section -->
|
||||
<section class="mb-12 sm:mb-16 md:mb-20">
|
||||
<div class="text-center mb-8 sm:mb-12">
|
||||
<h2
|
||||
class="text-2xl sm:text-3xl font-bold mb-3 sm:mb-4 text-text"
|
||||
>
|
||||
IPFS Integration
|
||||
</h2>
|
||||
<p
|
||||
class="text-lg sm:text-xl text-text-secondary max-w-3xl mx-auto"
|
||||
>
|
||||
Experience the power of decentralized content storage and
|
||||
retrieval with IPFS.
|
||||
</p>
|
||||
|
||||
<div class="mt-6">
|
||||
<Button
|
||||
variant="primary"
|
||||
size="lg"
|
||||
on:click={() => (showIPFSDemo = !showIPFSDemo)}
|
||||
>
|
||||
{showIPFSDemo ? "Hide IPFS Demo" : "Show IPFS Demo"}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{#if showIPFSDemo}
|
||||
<IPFSDemo />
|
||||
{/if}
|
||||
</section>
|
||||
<div class="p-8 text-center">
|
||||
<h2 class="text-2xl sm:text-3xl font-bold mb-4 text-text">
|
||||
Welcome to SecureWeb
|
||||
</h2>
|
||||
<p class="text-lg text-text-secondary max-w-3xl mx-auto">
|
||||
A decentralized web platform with IPFS integration and Blake
|
||||
hashing for content security.
|
||||
</p>
|
||||
<p class="mt-4 text-text-secondary">
|
||||
Use the sidebar navigation to explore the content and demos.
|
||||
</p>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
@@ -4,6 +4,8 @@
|
||||
import Footer from "./Footer.svelte";
|
||||
import NavDataProvider from "./NavDataProvider.svelte";
|
||||
import Home from "./Home.svelte";
|
||||
import BlakeHashDemo from "./BlakeHashDemo.svelte";
|
||||
import IPFSDemo from "./IPFSDemo.svelte";
|
||||
import { onMount } from "svelte";
|
||||
import ThemeProvider from "../lib/theme/ThemeProvider.svelte";
|
||||
|
||||
@@ -82,7 +84,15 @@
|
||||
sidebarVisible && !isMobile ? "md:ml-64" : "ml-0"
|
||||
}`}
|
||||
>
|
||||
{#if selectedContentPath}
|
||||
{#if selectedContentPath === "demos/blake-hash-demo"}
|
||||
<div class="p-4">
|
||||
<BlakeHashDemo />
|
||||
</div>
|
||||
{:else if selectedContentPath === "demos/ipfs-demo"}
|
||||
<div class="p-4">
|
||||
<IPFSDemo />
|
||||
</div>
|
||||
{:else if selectedContentPath}
|
||||
<Home contentPath={selectedContentPath} />
|
||||
{:else}
|
||||
<slot />
|
||||
|
168
sweb/src/services/content-processor.service.ts
Normal file
168
sweb/src/services/content-processor.service.ts
Normal file
@@ -0,0 +1,168 @@
|
||||
/**
|
||||
* Content Processing Service
|
||||
* Implements the content processing pipeline as described in the specs
|
||||
* Uses Blake hashing for content integrity and encryption key generation
|
||||
*/
|
||||
|
||||
import { cryptoService } from './crypto.service';
|
||||
import { ipfsService } from './ipfs.service';
|
||||
|
||||
/**
|
||||
* Interface for processed content metadata
|
||||
*/
|
||||
interface ProcessedContentMetadata {
|
||||
originalFilename: string;
|
||||
normalizedFilename: string;
|
||||
blakeHash: string;
|
||||
ipfsCid: string;
|
||||
combinedKey: string;
|
||||
contentType: string;
|
||||
size: number;
|
||||
timestamp: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Service for processing content files
|
||||
* Implements the content processing pipeline:
|
||||
* 1. File discovery
|
||||
* 2. Filename normalization
|
||||
* 3. Original content hashing (Blake)
|
||||
* 4. Content encryption
|
||||
* 5. Encrypted content upload to IPFS
|
||||
*/
|
||||
class ContentProcessorService {
|
||||
/**
|
||||
* Process a file through the content processing pipeline
|
||||
* @param file - File to process
|
||||
* @returns Promise<ProcessedContentMetadata> - Metadata of the processed content
|
||||
*/
|
||||
async processFile(file: File): Promise<ProcessedContentMetadata> {
|
||||
try {
|
||||
// Step 1: Get file information
|
||||
const originalFilename = file.name;
|
||||
|
||||
// Step 2: Normalize filename (lowercase and snake_case)
|
||||
const normalizedFilename = this.normalizeFilename(originalFilename);
|
||||
|
||||
// Step 3: Hash the original content using Blake3
|
||||
const blakeHash = await cryptoService.hashFileBlake3AsHex(file);
|
||||
|
||||
// Step 4: Encrypt the content using the Blake hash as the key
|
||||
// Note: This is a placeholder for actual encryption implementation
|
||||
const encryptedContent = await this.encryptContent(file, blakeHash);
|
||||
|
||||
// Step 5: Upload the encrypted content to IPFS
|
||||
const ipfsCid = await ipfsService.uploadContent(encryptedContent);
|
||||
|
||||
// Create the combined key (Blake hash + IPFS CID)
|
||||
const combinedKey = cryptoService.combineBlakeHashAndIpfsCid(blakeHash, ipfsCid);
|
||||
|
||||
// Return the metadata
|
||||
return {
|
||||
originalFilename,
|
||||
normalizedFilename,
|
||||
blakeHash,
|
||||
ipfsCid,
|
||||
combinedKey,
|
||||
contentType: file.type,
|
||||
size: file.size,
|
||||
timestamp: Date.now()
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('Error processing file:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize a filename to lowercase and snake_case
|
||||
* @param filename - Original filename
|
||||
* @returns Normalized filename
|
||||
*/
|
||||
normalizeFilename(filename: string): string {
|
||||
// Remove file extension
|
||||
const parts = filename.split('.');
|
||||
const extension = parts.pop() || '';
|
||||
let name = parts.join('.');
|
||||
|
||||
// Convert to lowercase
|
||||
name = name.toLowerCase();
|
||||
|
||||
// Replace spaces and special characters with underscores
|
||||
name = name.replace(/[^a-z0-9]/g, '_');
|
||||
|
||||
// Replace multiple underscores with a single one
|
||||
name = name.replace(/_+/g, '_');
|
||||
|
||||
// Remove leading and trailing underscores
|
||||
name = name.replace(/^_+|_+$/g, '');
|
||||
|
||||
// Add extension back if it exists
|
||||
if (extension) {
|
||||
name = `${name}.${extension.toLowerCase()}`;
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encrypt content using the Blake hash as the key
|
||||
* This is a placeholder for actual encryption implementation
|
||||
* @param file - File to encrypt
|
||||
* @param key - Encryption key (Blake hash)
|
||||
* @returns Promise<string> - Encrypted content as string
|
||||
*/
|
||||
async encryptContent(file: File, key: string): Promise<string> {
|
||||
// TODO: Implement actual encryption
|
||||
// For now, we'll just return a mock encrypted content
|
||||
// This should be replaced with actual encryption using the Blake hash as the key
|
||||
|
||||
// Convert the file to a string
|
||||
const arrayBuffer = await file.arrayBuffer();
|
||||
const contentBytes = new Uint8Array(arrayBuffer);
|
||||
|
||||
// Mock encryption by XORing with the key bytes
|
||||
// This is NOT secure and is only for demonstration purposes
|
||||
const keyBytes = cryptoService.hexToBytes(key);
|
||||
const encryptedBytes = new Uint8Array(contentBytes.length);
|
||||
|
||||
for (let i = 0; i < contentBytes.length; i++) {
|
||||
encryptedBytes[i] = contentBytes[i] ^ keyBytes[i % keyBytes.length];
|
||||
}
|
||||
|
||||
// Convert to base64 for storage
|
||||
return btoa(String.fromCharCode.apply(null, Array.from(encryptedBytes)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrypt content using the Blake hash as the key
|
||||
* This is a placeholder for actual decryption implementation
|
||||
* @param encryptedContent - Encrypted content as string
|
||||
* @param key - Decryption key (Blake hash)
|
||||
* @returns Promise<Uint8Array> - Decrypted content as Uint8Array
|
||||
*/
|
||||
async decryptContent(encryptedContent: string, key: string): Promise<Uint8Array> {
|
||||
// TODO: Implement actual decryption
|
||||
// For now, we'll just return a mock decrypted content
|
||||
// This should be replaced with actual decryption using the Blake hash as the key
|
||||
|
||||
// Convert the base64 string to bytes
|
||||
const encryptedBytes = new Uint8Array(
|
||||
atob(encryptedContent).split('').map(c => c.charCodeAt(0))
|
||||
);
|
||||
|
||||
// Mock decryption by XORing with the key bytes
|
||||
// This is NOT secure and is only for demonstration purposes
|
||||
const keyBytes = cryptoService.hexToBytes(key);
|
||||
const decryptedBytes = new Uint8Array(encryptedBytes.length);
|
||||
|
||||
for (let i = 0; i < encryptedBytes.length; i++) {
|
||||
decryptedBytes[i] = encryptedBytes[i] ^ keyBytes[i % keyBytes.length];
|
||||
}
|
||||
|
||||
return decryptedBytes;
|
||||
}
|
||||
}
|
||||
|
||||
// Create a singleton instance
|
||||
export const contentProcessorService = new ContentProcessorService();
|
125
sweb/src/services/crypto.service.ts
Normal file
125
sweb/src/services/crypto.service.ts
Normal file
@@ -0,0 +1,125 @@
|
||||
/**
|
||||
* Cryptography Service
|
||||
* Provides cryptographic functions for content processing
|
||||
* Implements Blake hashing algorithm for content integrity and encryption key generation
|
||||
*/
|
||||
|
||||
import { blake3 } from '@noble/hashes/blake3';
|
||||
import { bytesToHex, hexToBytes, utf8ToBytes } from '@noble/hashes/utils';
|
||||
|
||||
/**
|
||||
* Service for cryptographic operations
|
||||
* Provides methods for hashing, encryption, and decryption
|
||||
*/
|
||||
class CryptoService {
|
||||
/**
|
||||
* Hash content using Blake3 algorithm
|
||||
* @param content - Content to hash as Uint8Array
|
||||
* @returns Blake3 hash as Uint8Array
|
||||
*/
|
||||
hashBlake3(content: Uint8Array): Uint8Array {
|
||||
return blake3(content);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hash content using Blake3 algorithm with custom output length
|
||||
* @param content - Content to hash as Uint8Array
|
||||
* @param outputLength - Length of the output hash in bytes
|
||||
* @returns Blake3 hash as Uint8Array
|
||||
*/
|
||||
hashBlake3WithLength(content: Uint8Array, outputLength: number): Uint8Array {
|
||||
return blake3(content, { dkLen: outputLength });
|
||||
}
|
||||
|
||||
/**
|
||||
* Hash string content using Blake3 algorithm
|
||||
* @param content - Content to hash as string
|
||||
* @returns Blake3 hash as Uint8Array
|
||||
*/
|
||||
hashStringBlake3(content: string): Uint8Array {
|
||||
const contentBytes = utf8ToBytes(content);
|
||||
return this.hashBlake3(contentBytes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hash string content using Blake3 algorithm and return as hex string
|
||||
* @param content - Content to hash as string
|
||||
* @returns Blake3 hash as hex string
|
||||
*/
|
||||
hashStringBlake3AsHex(content: string): string {
|
||||
const hash = this.hashStringBlake3(content);
|
||||
return bytesToHex(hash);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hash file content using Blake3 algorithm
|
||||
* @param file - File to hash
|
||||
* @returns Promise<Uint8Array> - Blake3 hash as Uint8Array
|
||||
*/
|
||||
async hashFileBlake3(file: File): Promise<Uint8Array> {
|
||||
const buffer = await file.arrayBuffer();
|
||||
const contentBytes = new Uint8Array(buffer);
|
||||
return this.hashBlake3(contentBytes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hash file content using Blake3 algorithm and return as hex string
|
||||
* @param file - File to hash
|
||||
* @returns Promise<string> - Blake3 hash as hex string
|
||||
*/
|
||||
async hashFileBlake3AsHex(file: File): Promise<string> {
|
||||
const hash = await this.hashFileBlake3(file);
|
||||
return bytesToHex(hash);
|
||||
}
|
||||
|
||||
/**
|
||||
* Combine Blake hash and IPFS CID into a single key string
|
||||
* Format: <blake_hash>:<ipfs_cid>
|
||||
* @param blakeHash - Blake hash as hex string
|
||||
* @param ipfsCid - IPFS CID as string
|
||||
* @returns Combined key string
|
||||
*/
|
||||
combineBlakeHashAndIpfsCid(blakeHash: string, ipfsCid: string): string {
|
||||
return `${blakeHash}:${ipfsCid}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Split combined key string into Blake hash and IPFS CID
|
||||
* @param combinedKey - Combined key string in format <blake_hash>:<ipfs_cid>
|
||||
* @returns Object with blakeHash and ipfsCid
|
||||
*/
|
||||
splitCombinedKey(combinedKey: string): { blakeHash: string; ipfsCid: string } {
|
||||
const [blakeHash, ipfsCid] = combinedKey.split(':');
|
||||
return { blakeHash, ipfsCid };
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert hex string to Uint8Array
|
||||
* @param hex - Hex string
|
||||
* @returns Uint8Array
|
||||
*/
|
||||
hexToBytes(hex: string): Uint8Array {
|
||||
return hexToBytes(hex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert Uint8Array to hex string
|
||||
* @param bytes - Uint8Array
|
||||
* @returns Hex string
|
||||
*/
|
||||
bytesToHex(bytes: Uint8Array): string {
|
||||
return bytesToHex(bytes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert string to Uint8Array using UTF-8 encoding
|
||||
* @param str - String to convert
|
||||
* @returns Uint8Array
|
||||
*/
|
||||
stringToBytes(str: string): Uint8Array {
|
||||
return utf8ToBytes(str);
|
||||
}
|
||||
}
|
||||
|
||||
// Create a singleton instance
|
||||
export const cryptoService = new CryptoService();
|
Reference in New Issue
Block a user