<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="/feed.xml" rel="self" type="application/atom+xml" /><link href="/" rel="alternate" type="text/html" /><updated>2025-07-26T15:15:04+00:00</updated><id>/feed.xml</id><title type="html">Truong’s blog</title><subtitle>A blog of a self-motivated techie.</subtitle><author><name>Truong</name></author><entry><title type="html">Elliptic Curve Cryptography Toolbox.</title><link href="/tools/ecc" rel="alternate" type="text/html" title="Elliptic Curve Cryptography Toolbox." /><published>2025-07-26T00:00:00+00:00</published><updated>2025-07-26T00:00:00+00:00</updated><id>/tools/ECC-toolbox</id><content type="html" xml:base="/tools/ecc"><![CDATA[<h2 id="ec-cryptography-toolbox">EC Cryptography Toolbox</h2>

<p>This tool calculates the public key from a private key using elliptic curve cryptography with the NIST P-256 curve.</p>

<div class="notice--info">
<strong>Info:</strong> Enter your private key as a hexadecimal string (64 characters for P-256). The tool will calculate the corresponding public key coordinates.
</div>

<form id="crypto-form">
  <div class="form-group">
    <label for="curve"><strong>Elliptic Curve:</strong></label>
    <select id="curve" class="form-control">
      <option value="P-256">NIST P-256 (secp256r1)</option>
    </select>
  </div>

  <div class="form-group">
    <label for="privateKey"><strong>Private Key A (Hex):</strong></label>
    <input type="text" id="privateKey" class="form-control" placeholder="Enter 64-character hexadecimal private key for Party A" maxlength="64" style="font-family: monospace;" />
    <small class="form-text text-muted">Example: c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5</small>
  </div>

  <div class="form-group">
    <label for="privateKeyB"><strong>Private Key B (Hex):</strong></label>
    <input type="text" id="privateKeyB" class="form-control" placeholder="Enter 64-character hexadecimal private key for Party B" maxlength="64" style="font-family: monospace;" />
    <small class="form-text text-muted">Example: f8f8a2f43c8376ccb0871305060d7b27b0554d2cc72bccf41b2705608452f315</small>
  </div>

  <div class="text-center">
    <button type="button" onclick="loadSampleKeys()" class="btn btn--info btn--small">Load Sample Keys</button>
    <button type="button" onclick="calculatePublicKey()" class="btn btn--primary">Calculate Public Keys</button>
    <button type="button" onclick="performKeyExchange()" class="btn btn--success">🔄 Key Exchange (ECDH)</button>
  </div>
</form>

<div id="results" style="margin-top: 2rem;">
  <h3>Public Keys (Uncompressed Format)</h3>
  
  <div class="row">
    <div class="col-md-6">
      <h4>Party A Public Key</h4>
      <div class="form-group">
        <label for="publicKeyAX"><strong>X Coordinate:</strong></label>
        <textarea id="publicKeyAX" class="form-control" readonly="" rows="2" placeholder="Party A X coordinate..." style="font-family: monospace; font-size: 0.9rem;"></textarea>
      </div>
      <div class="form-group">
        <label for="publicKeyAY"><strong>Y Coordinate:</strong></label>
        <textarea id="publicKeyAY" class="form-control" readonly="" rows="2" placeholder="Party A Y coordinate..." style="font-family: monospace; font-size: 0.9rem;"></textarea>
      </div>
    </div>
    
    <div class="col-md-6">
      <h4>Party B Public Key</h4>
      <div class="form-group">
        <label for="publicKeyBX"><strong>X Coordinate:</strong></label>
        <textarea id="publicKeyBX" class="form-control" readonly="" rows="2" placeholder="Party B X coordinate..." style="font-family: monospace; font-size: 0.9rem;"></textarea>
      </div>
      <div class="form-group">
        <label for="publicKeyBY"><strong>Y Coordinate:</strong></label>
        <textarea id="publicKeyBY" class="form-control" readonly="" rows="2" placeholder="Party B Y coordinate..." style="font-family: monospace; font-size: 0.9rem;"></textarea>
      </div>
    </div>
  </div>
  
  <div style="margin-top: 2rem;">
    <h3>🔐 ECDH Shared Secret</h3>
    <div class="form-group">
      <label for="sharedSecret"><strong>Shared Secret (X Coordinate):</strong></label>
      <textarea id="sharedSecret" class="form-control" readonly="" rows="2" placeholder="Shared secret will appear here after key exchange..." style="font-family: monospace; font-size: 0.9rem; background-color: #f8f9fa;"></textarea>
      <small class="form-text text-muted">In ECDH, only the X coordinate of the shared point is typically used as the shared secret.</small>
    </div>
  </div>
</div>

<div id="error"></div>

<script>
// NIST P-256 curve parameters
const P256 = {
    // Prime field
    p: BigInt('0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff'),
    // Curve parameter a
    a: BigInt('0xffffffff00000001000000000000000000000000fffffffffffffffffffffffc'),
    // Curve parameter b  
    b: BigInt('0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b'),
    // Order of the base point
    n: BigInt('0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551'),
    // Base point coordinates
    Gx: BigInt('0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296'),
    Gy: BigInt('0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5')
};

// Modular arithmetic functions
function mod(a, m) {
    return ((a % m) + m) % m;
}

function modInverse(a, m) {
    if (a < 0n) a = mod(a, m);
    
    let [old_r, r] = [a, m];
    let [old_s, s] = [1n, 0n];
    
    while (r !== 0n) {
        const quotient = old_r / r;
        [old_r, r] = [r, old_r - quotient * r];
        [old_s, s] = [s, old_s - quotient * s];
    }
    
    return mod(old_s, m);
}

// Point addition on elliptic curve
function pointAdd(p1, p2) {
    if (!p1) return p2;
    if (!p2) return p1;
    
    const [x1, y1] = p1;
    const [x2, y2] = p2;
    
    if (x1 === x2) {
        if (y1 === y2) {
            // Point doubling
            const s = mod((3n * x1 * x1 + P256.a) * modInverse(2n * y1, P256.p), P256.p);
            const x3 = mod(s * s - 2n * x1, P256.p);
            const y3 = mod(s * (x1 - x3) - y1, P256.p);
            return [x3, y3];
        } else {
            // Points are inverses
            return null;
        }
    }
    
    const s = mod((y2 - y1) * modInverse(x2 - x1, P256.p), P256.p);
    const x3 = mod(s * s - x1 - x2, P256.p);
    const y3 = mod(s * (x1 - x3) - y1, P256.p);
    
    return [x3, y3];
}

// Scalar multiplication using double-and-add
function scalarMult(k, point) {
    if (k === 0n) return null;
    if (k === 1n) return point;
    
    let result = null;
    let addend = point;
    
    while (k > 0n) {
        if (k & 1n) {
            result = pointAdd(result, addend);
        }
        addend = pointAdd(addend, addend);
        k >>= 1n;
    }
    
    return result;
}

function loadSampleKeys() {
    document.getElementById('privateKey').value = 'c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5';
    document.getElementById('privateKeyB').value = 'f8f8a2f43c8376ccb0871305060d7b27b0554d2cc72bccf41b2705608452f315';
}

function updatePublicKeysDisplay(privateKeyA, privateKeyB) {
    const publicKeyAX = document.getElementById('publicKeyAX');
    const publicKeyAY = document.getElementById('publicKeyAY');
    const publicKeyBX = document.getElementById('publicKeyBX');
    const publicKeyBY = document.getElementById('publicKeyBY');
    
    // Calculate and display Party A public key
    if (privateKeyA) {
        const publicKeyAPoint = scalarMult(privateKeyA, [P256.Gx, P256.Gy]);
        if (publicKeyAPoint) {
            const [qax, qay] = publicKeyAPoint;
            publicKeyAX.value = qax.toString(16).padStart(64, '0');
            publicKeyAY.value = qay.toString(16).padStart(64, '0');
        }
    }
    
    // Calculate and display Party B public key
    if (privateKeyB) {
        const publicKeyBPoint = scalarMult(privateKeyB, [P256.Gx, P256.Gy]);
        if (publicKeyBPoint) {
            const [qbx, qby] = publicKeyBPoint;
            publicKeyBX.value = qbx.toString(16).padStart(64, '0');
            publicKeyBY.value = qby.toString(16).padStart(64, '0');
        }
    }
}

function calculatePublicKey() {
    const errorDiv = document.getElementById('error');
    const publicKeyAX = document.getElementById('publicKeyAX');
    const publicKeyAY = document.getElementById('publicKeyAY');
    const publicKeyBX = document.getElementById('publicKeyBX');
    const publicKeyBY = document.getElementById('publicKeyBY');
    
    // Clear previous results (but NOT the shared secret)
    errorDiv.innerHTML = '';
    publicKeyAX.value = '';
    publicKeyAY.value = '';
    publicKeyBX.value = '';
    publicKeyBY.value = '';
    // DON'T clear shared secret: document.getElementById('sharedSecret').value = '';
    
    try {
        const privateKeyAHex = document.getElementById('privateKey').value.trim();
        const privateKeyBHex = document.getElementById('privateKeyB').value.trim();
        
        let privateKeyA = null;
        let privateKeyB = null;
        
        // Calculate Party A public key
        if (privateKeyAHex) {
            validatePrivateKey(privateKeyAHex, 'Private Key A');
            privateKeyA = BigInt('0x' + privateKeyAHex);
            const publicKeyAPoint = scalarMult(privateKeyA, [P256.Gx, P256.Gy]);
            
            if (publicKeyAPoint) {
                const [qax, qay] = publicKeyAPoint;
                publicKeyAX.value = qax.toString(16).padStart(64, '0');
                publicKeyAY.value = qay.toString(16).padStart(64, '0');
            }
        }
        
        // Calculate Party B public key
        if (privateKeyBHex) {
            validatePrivateKey(privateKeyBHex, 'Private Key B');
            privateKeyB = BigInt('0x' + privateKeyBHex);
            const publicKeyBPoint = scalarMult(privateKeyB, [P256.Gx, P256.Gy]);
            
            if (publicKeyBPoint) {
                const [qbx, qby] = publicKeyBPoint;
                publicKeyBX.value = qbx.toString(16).padStart(64, '0');
                publicKeyBY.value = qby.toString(16).padStart(64, '0');
            }
        }
        
    } catch (error) {
        errorDiv.innerHTML = '<div class="notice--danger"><strong>Error:</strong> ' + error.message + '</div>';
    }
}

function validatePrivateKey(keyHex, keyName) {
    if (!keyHex) {
        throw new Error(`Please enter ${keyName}`);
    }
    
    if (!/^[0-9a-fA-F]+$/.test(keyHex)) {
        throw new Error(`${keyName} must contain only hexadecimal characters (0-9, a-f, A-F)`);
    }
    
    if (keyHex.length !== 64) {
        throw new Error(`${keyName} must be exactly 64 hexadecimal characters (32 bytes) for P-256`);
    }
    
    const privateKey = BigInt('0x' + keyHex);
    if (privateKey <= 0n || privateKey >= P256.n) {
        throw new Error(`${keyName} must be between 1 and n-1 where n is the curve order`);
    }
}

function performKeyExchange() {
    const errorDiv = document.getElementById('error');
    const sharedSecretField = document.getElementById('sharedSecret');
    
    // Debug: Check if we can find the shared secret field
    console.log('Shared secret field found:', !!sharedSecretField);
    if (!sharedSecretField) {
        console.error('Could not find sharedSecret element!');
        return;
    }
    
    // Clear previous error
    errorDiv.innerHTML = '';
    sharedSecretField.value = '';
    
    try {
        const privateKeyAHex = document.getElementById('privateKey').value.trim();
        const privateKeyBHex = document.getElementById('privateKeyB').value.trim();
        
        // Validate both private keys
        validatePrivateKey(privateKeyAHex, 'Private Key A');
        validatePrivateKey(privateKeyBHex, 'Private Key B');
        
        const privateKeyA = BigInt('0x' + privateKeyAHex);
        const privateKeyB = BigInt('0x' + privateKeyBHex);
        
        console.log('Private Key A:', privateKeyAHex);
        console.log('Private Key B:', privateKeyBHex);
        
        // Calculate public keys first
        const publicKeyA = scalarMult(privateKeyA, [P256.Gx, P256.Gy]);
        const publicKeyB = scalarMult(privateKeyB, [P256.Gx, P256.Gy]);
        
        if (!publicKeyA || !publicKeyB) {
            throw new Error('Failed to calculate public keys');
        }
        
        console.log('Public Key A:', publicKeyA[0].toString(16), publicKeyA[1].toString(16));
        console.log('Public Key B:', publicKeyB[0].toString(16), publicKeyB[1].toString(16));
        
        // Perform ECDH: 
        // Party A calculates: sharedSecret = privateKeyA * publicKeyB
        // Party B calculates: sharedSecret = privateKeyB * publicKeyA
        // Both should get the same result
        const sharedSecretA = scalarMult(privateKeyA, publicKeyB);
        const sharedSecretB = scalarMult(privateKeyB, publicKeyA);
        
        console.log('Shared Secret A:', sharedSecretA ? sharedSecretA[0].toString(16) : 'null');
        console.log('Shared Secret B:', sharedSecretB ? sharedSecretB[0].toString(16) : 'null');
        
        if (!sharedSecretA || !sharedSecretB) {
            throw new Error('Failed to calculate shared secret. Check browser console for details.');
        }
        
        // Verify both parties get the same shared secret
        if (sharedSecretA[0] !== sharedSecretB[0] || sharedSecretA[1] !== sharedSecretB[1]) {
            throw new Error(`Shared secret mismatch! A: ${sharedSecretA[0].toString(16)}, B: ${sharedSecretB[0].toString(16)}`);
        }
        
        console.log('ECDH calculation successful. Both parties have matching shared secrets.');
        console.log('Shared secret point:', sharedSecretA[0].toString(16), sharedSecretA[1].toString(16));
        
        // Display the shared secret (typically only X coordinate is used)
        const sharedSecretHex = sharedSecretA[0].toString(16).padStart(64, '0');
        
        // Set the shared secret first, before updating public keys
        sharedSecretField.value = sharedSecretHex;
        
        // Update public keys display (but don't clear the shared secret)
        updatePublicKeysDisplay(privateKeyA, privateKeyB);
        
        // Additional debug to ensure the field is being set
        console.log('Setting shared secret field to:', sharedSecretHex);
        console.log('Shared secret field element:', sharedSecretField);
        console.log('Field value after setting:', sharedSecretField.value);
        console.log('Field innerHTML after setting:', sharedSecretField.innerHTML);
        
        // Also update public keys if they weren't calculated yet
        calculatePublicKey();
        
        // Add success message
        errorDiv.innerHTML = '<div class="notice--success"><strong>Success!</strong> ECDH key exchange completed. Both parties now share the same secret.</div>';
        
    } catch (error) {
        console.error('ECDH Error:', error);
        errorDiv.innerHTML = '<div class="notice--danger"><strong>Error:</strong> ' + error.message + '</div>';
    }
}

// Allow Enter key to trigger calculation
document.getElementById('privateKey').addEventListener('keypress', function(e) {
    if (e.key === 'Enter') {
        calculatePublicKey();
    }
});

document.getElementById('privateKeyB').addEventListener('keypress', function(e) {
    if (e.key === 'Enter') {
        calculatePublicKey();
    }
});
</script>

<h2 id="ecdh-key-exchange">ECDH Key Exchange</h2>

<p>The Elliptic Curve Diffie-Hellman (ECDH) key exchange allows two parties to establish a shared secret over an insecure channel:</p>

<ol>
  <li><strong>Party A</strong> generates private key <code class="language-plaintext highlighter-rouge">a</code> and calculates public key <code class="language-plaintext highlighter-rouge">A = a × G</code></li>
  <li><strong>Party B</strong> generates private key <code class="language-plaintext highlighter-rouge">b</code> and calculates public key <code class="language-plaintext highlighter-rouge">B = b × G</code></li>
  <li>Both parties exchange their public keys</li>
  <li><strong>Party A</strong> calculates shared secret: <code class="language-plaintext highlighter-rouge">S = a × B</code></li>
  <li><strong>Party B</strong> calculates shared secret: <code class="language-plaintext highlighter-rouge">S = b × A</code></li>
  <li>Both parties arrive at the same shared secret <code class="language-plaintext highlighter-rouge">S = a × b × G</code></li>
</ol>

<h3 id="security-properties">Security Properties</h3>

<ul>
  <li>The shared secret cannot be derived by an eavesdropper who only knows the public keys</li>
  <li>Based on the computational difficulty of the Elliptic Curve Discrete Logarithm Problem (ECDLP)</li>
  <li>The X coordinate of the shared point is typically used as the shared secret for further cryptographic operations</li>
</ul>

<h2 id="how-it-works">How It Works</h2>

<p>The tool implements elliptic curve point multiplication using the NIST P-256 curve parameters:</p>

<ul>
  <li><strong>Prime field</strong>: <code class="language-plaintext highlighter-rouge">p = 2^256 - 2^224 + 2^192 + 2^96 - 1</code></li>
  <li><strong>Curve equation</strong>: <code class="language-plaintext highlighter-rouge">y² = x³ - 3x + b (mod p)</code></li>
  <li><strong>Base point</strong>: Pre-defined generator point G</li>
  <li><strong>Public key calculation</strong>: <code class="language-plaintext highlighter-rouge">Q = k × G</code> where k is the private key</li>
</ul>

<h3 id="key-features">Key Features</h3>

<ul>
  <li><strong>Input validation</strong>: Ensures private key is valid hex and within curve order</li>
  <li><strong>Secure arithmetic</strong>: Uses BigInt for precise modular arithmetic</li>
  <li><strong>Efficient algorithm</strong>: Double-and-add method for scalar multiplication</li>
  <li><strong>Clear output</strong>: Separate display of X and Y coordinates</li>
</ul>

<h3 id="security-notes">Security Notes</h3>

<ul>
  <li>Private keys must be randomly generated and kept secure</li>
  <li>This tool is for educational/development purposes</li>
  <li>Never enter real private keys in web tools for production use</li>
</ul>

<hr />

<p><em>This tool implements the mathematical foundations of elliptic curve cryptography as specified in NIST standards.</em></p>]]></content><author><name>Truong</name></author><summary type="html"><![CDATA[EC Cryptography Toolbox This tool calculates the public key from a private key using elliptic curve cryptography with the NIST P-256 curve. Info: Enter your private key as a hexadecimal string (64 characters for P-256). The tool will calculate the corresponding public key coordinates. Elliptic Curve: NIST P-256 (secp256r1) Private Key A (Hex): Example: c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5 Private Key B (Hex): Example: f8f8a2f43c8376ccb0871305060d7b27b0554d2cc72bccf41b2705608452f315 Load Sample Keys Calculate Public Keys 🔄 Key Exchange (ECDH) Public Keys (Uncompressed Format) Party A Public Key X Coordinate: Y Coordinate: Party B Public Key X Coordinate: Y Coordinate: 🔐 ECDH Shared Secret Shared Secret (X Coordinate): In ECDH, only the X coordinate of the shared point is typically used as the shared secret. ECDH Key Exchange The Elliptic Curve Diffie-Hellman (ECDH) key exchange allows two parties to establish a shared secret over an insecure channel: Party A generates private key a and calculates public key A = a × G Party B generates private key b and calculates public key B = b × G Both parties exchange their public keys Party A calculates shared secret: S = a × B Party B calculates shared secret: S = b × A Both parties arrive at the same shared secret S = a × b × G Security Properties The shared secret cannot be derived by an eavesdropper who only knows the public keys Based on the computational difficulty of the Elliptic Curve Discrete Logarithm Problem (ECDLP) The X coordinate of the shared point is typically used as the shared secret for further cryptographic operations How It Works The tool implements elliptic curve point multiplication using the NIST P-256 curve parameters: Prime field: p = 2^256 - 2^224 + 2^192 + 2^96 - 1 Curve equation: y² = x³ - 3x + b (mod p) Base point: Pre-defined generator point G Public key calculation: Q = k × G where k is the private key Key Features Input validation: Ensures private key is valid hex and within curve order Secure arithmetic: Uses BigInt for precise modular arithmetic Efficient algorithm: Double-and-add method for scalar multiplication Clear output: Separate display of X and Y coordinates Security Notes Private keys must be randomly generated and kept secure This tool is for educational/development purposes Never enter real private keys in web tools for production use This tool implements the mathematical foundations of elliptic curve cryptography as specified in NIST standards.]]></summary></entry><entry><title type="html">Toyz password generator</title><link href="/tools/passgen" rel="alternate" type="text/html" title="Toyz password generator" /><published>2024-02-10T00:00:00+00:00</published><updated>2024-02-10T00:00:00+00:00</updated><id>/tools/Password-KDF</id><content type="html" xml:base="/tools/passgen"><![CDATA[<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Password Derivation</title>
</head>
<body>

<h2>Password Generator based on AES-MP - Experimental, NOT SECURED!!!</h2>

<form id="passwordForm">
  <label for="inputString">Alphanumeric String:</label><br />
  <input type="text" id="inputString" name="inputString" required="" /><br />
  <label for="seed">Seed:</label><br />
  <input type="text" id="seed" name="seed" required="" /><br /><br />
  <button type="button" onclick="derivePassword()">Generate Password</button>
</form>

<div id="output"></div>

<script>
function derivePassword() {
  var inputString = document.getElementById("inputString").value;
  
  var padString = padDataWithPKCS7(inputString);
  var seed = document.getElementById("seed").value;
  
  var prePass = calculateAESBlockCipher(seed, padString);
  handleEncryption();
  // Password derivation function
  var password = deriveBase64Password(prePass);
  
  document.getElementById("output").innerHTML = "Derived Password (Base64): " + password;
}

async function calculateAESBlockCipher(key, data) {
  try {
    // Import the AES key
    const importedKey = await window.crypto.subtle.importKey(
      "raw", 
      key, 
      { name: "AES-ECB" }, 
      false, 
      ["encrypt", "decrypt"]
    );

    // Encrypt the data using AES-ECB
    const encryptedData = await window.crypto.subtle.encrypt(
      { name: "AES-ECB" }, 
      importedKey, 
      data
    );

    // Return the encrypted data
    return encryptedData;
  } catch (error) {
    console.error('AES encryption failed:', error);
    return null;
  }
}

function padDataWithPKCS7(data) {
  const blockSize = 16; // AES block size is 16 bytes
  const paddingLength = blockSize - (data.length % blockSize);
  const paddingValue = paddingLength;
  const paddedData = new Uint8Array([...data, ...Array(paddingLength).fill(paddingValue)]);
  return paddedData;
}

async function handleEncryption() {
  const key = new Uint8Array(16); // Example AES key
  const data = new Uint8Array([/* Your data here */]); // Example data
  
  try {
    const encryptedData = await calculateAESBlockCipher(key, data);
    document.getElementById("output").innerText = "Encrypted Data: " + uint8ArrayToHexString(new Uint8Array(encryptedData));
  } catch (error) {
    console.error('Encryption failed:', error);
    document.getElementById("output").innerText = "Encryption failed";
  }
}

function uint8ArrayToHexString(uint8Array) {
  return Array.from(uint8Array).map(byte => byte.toString(16).padStart(2, '0')).join('');
}


function deriveBase64Password(inputString) {
  // Encoding the combined string to base64
  var password = btoa(inputString);
  return password;
}
</script>

</body>
</html>]]></content><author><name>Truong</name></author><summary type="html"><![CDATA[Password Derivation Password Generator based on AES-MP - Experimental, NOT SECURED!!! Alphanumeric String: Seed: Generate Password]]></summary></entry><entry><title type="html">Tại sao kỹ sư hệ thống nhúng nên học ngôn ngữ assembly?</title><link href="/engineering/vietnamese/Why-should-learn-assembly/" rel="alternate" type="text/html" title="Tại sao kỹ sư hệ thống nhúng nên học ngôn ngữ assembly?" /><published>2024-01-13T00:00:00+00:00</published><updated>2024-01-13T00:00:00+00:00</updated><id>/engineering/vietnamese/Why-should-learn-assembly</id><content type="html" xml:base="/engineering/vietnamese/Why-should-learn-assembly/"><![CDATA[<p class="notice--info"><strong>Info Notice:</strong> Đây là bài viết đầu tiên tôi viết bằng tiếng Việt với mong muốn bài viết này đến được với nhiều đọc giả còn đang là sinh viên hoặc những kỹ sư trẻ đang làm ngành phần mềm nhúng. Bài viết này dựa trên bài viết <a href="https://rtos.dev/engineering/EABI/">EABI - Why any embedded software engineer should know about it.</a>. Mặc dù tôi đã cố gắng sử dụng nhiều từ vựng tiếng Việt nhất có thể, nhưng vì giới hạn của từ tiếng Việt đối với từ ngữ chuyên ngành nên tôi sẽ dùng từ ngữ tiếng Anh thay thế để cho giọng văn nghe sẽ tự nhiên với người đọc là những người làm kỹ sư hơn. .</p>

<h1 id="tại-sao-kỹ-sư-hệ-thống-nhúng-nên-học-assembly">Tại sao kỹ sư hệ thống nhúng nên học assembly?</h1>
<p>Tôi vốn không học ngành khoa học máy tính hay những ngành liên quan đến lập trình, nhưng may mắn tôi được học khóa kiến trúc máy tính và hợp ngữ (<code class="language-plaintext highlighter-rouge">Assembly</code>) khi còn học đại học, và may mắn hơn nữa khi tôi được học với một người thầy lớn tuổi và có nhiều kinh nghiệm với những CPU “cổ” (ví dụ như 8086). Có lẽ vì thầy lớn tuổi nên thầy đã trả qua một kỳ khi mà các ngôn ngữ cấp cao chưa mạnh, hay các MCU tại thời điểm thầy làm việc có bộ nhớ khá khiêm tốn, và thực sự thì các ứng dụng sử dụng MCU tại thời điểm đó còn chưa phức tạp như thời điểm viết bài viết này nên việc sử dụng <code class="language-plaintext highlighter-rouge">assembly</code> để lập trình ứng dụng vẫn là một công việc phổ biến và phù hợp thời ấy.</p>

<p>Nhưng hiện giờ đã là năm 2024, khi các MCU 32-bit đã rất rẻ và có nhiều bộ nhớ, các trình biên dịch ngôn ngữ <code class="language-plaintext highlighter-rouge">C</code> (<code class="language-plaintext highlighter-rouge">C</code> compiler) đã rất phổ biến và tối ưu, thư viện hỗ trợ cho các MCU cũng đã được phát triển rất nhiều, điều này giúp cho việc lập trình nhúng trở nên dễ tiếp cận hơn. Tuy nhiên, với khoảng thời gian 10 năm làm nhúng tại nhiều công ty và được tiếp xúc với nhiều đồng nghiệp từ các bạn mới tốt ngiệp (fresher) cho tới các expert có hơn 10 năm kinh nghiệm, tôi quan sát thấy rằng những kỹ sư có kiến thức nền tảng vững vàng và hiểu biết sâu sắc về hệ thống nhúng đều có khả năng đọc, hiểu và viết chương trình <code class="language-plaintext highlighter-rouge">assembly</code>.</p>

<p>Tôi sẽ liệt kê ra một vài trường hợp tại sao ngôn ngữ cấp cao (như <code class="language-plaintext highlighter-rouge">C</code>) không thể thay thế <code class="language-plaintext highlighter-rouge">assembly</code>.</p>
<ul>
  <li>Khi dự án làm việc với một MCU mới, chúng ta chỉ có tài liệu (Datasheet, user manual) và <code class="language-plaintext highlighter-rouge">C</code> compiler (bắt buộc phải có), và chỉ thế thôi, chúng ta không có IDE, không có BSP (Board Support Package), mọi thứ phải bắt đầu từ con số 0 (build from scratch).</li>
  <li>Khi bạn cần viết/sửa đổi core implementation của hệ điều hành (Việc này cũng khá phổ biến nếu dự án làm việc với in-house RTOS).</li>
  <li>Khi compiler bị lỗi!!! Đúng vậy, việc compiler bị lỗi khá là phổ biến nếu bạn code cho embedded đủ nhiều, kể cả compiler có bản quyền đắt tiền (Không một phần mềm nào là không có lỗi).</li>
  <li>Khi chúng ta muốn hiểu sâu về kiến trúc của một MCU/CPU, và <strong>đây là điều quan trọng nhất</strong>.</li>
</ul>

<p>Và ở phần tiếp theo, tôi sẽ trích lại một hồi ký của một kỹ sư lập trình nhúng giả tưởng, qua đó phản ánh cách mà assembly xuất hiện trong công việc của một kỹ sư lập trình nhúng. Đó có thể là tôi hoặc bạn trong những giai đoạn khác nhau của công việc, và mục đích của tôi là để nhấn mạnh việc cần thiết phải biết về ngôn ngữ assembly kể cả khi chúng ta hiếm khi sử dụng nó, nhưng khi chúng ta cần tới nó, chúng ta biết sẽ phải làm gì.</p>

<h1 id="nhật-ký-của-một-kỹ-sư-phần-mềm-nhúng">Nhật ký của một kỹ sư phần mềm nhúng.</h1>
<h2 id="sức-hấp-dẫn-bởi-sự-dễ-dàng-của-arduino">Sức hấp dẫn bởi sự dễ dàng của Arduino!</h2>
<p><em>- Ngày XX tháng YY năm ZZZZ</em></p>

<p>Vâng, với Arduino, bạn có thể mua các module cảm biến và một bộ khung robot về và … Voila, chúng ta đã có một project khá là cool. Bạn học được cách các sensor hoạt động như thế nào, bạn biết cách điều khiển các cánh quạt quay như thế nào để máy bay có thể bay lên , bay tiến hay bay lùi, bạn có một đồ án tốt nghiệp đồ sộ đáng tự hào khi bạn đã lập trình những tính năng phức tạp nhất, tất nhiên là trên Arduino … Cho đến khi bạn đi làm và bạn nhận ra, những dự án thực thụ không dùng Arduino. Bạn được giao cho một dự án với một con MCU bạn chưa gặp bao giờ, dự án không có IDE, mọi người viết code bằng bất cứ text editor nào (tất nhiên <strong>Notepad++</strong> luôn là sự lựa chọn số 1) và mọi người build code bằng command line (What the heck!!!). Bạn nhập cuộc khá dễ dàng, bạn follow coding guideline, và bạn đã build được project như mọi người. Tiếp theo, bạn được giao cho nhiệm vụ viết một driver cho một khối ngoại vi của dự án, bạn háo hức với lần đầu tiên bạn được thể hiện khả năng coding của mình. Bạn bắt đầu viết những dòng code đầu tiên, bạn được mọi người trong team hướng dẫn cho cách sử dụng debugger, mọi thứ khá suôn sẻ. Và chuyện gì rồi cũng sẽ đến, bạn thấy chương trình của mình không chạy, bạn muốn debug, bạn không có hàm print của arduino, bạn phải làm quen với việc sử dụng debugger, cũng không phải việc gì quá khó khăn, ngoại trừ việc bạn  thấy chương trình của mình viết chạy không theo thứ tự từ trên xuống dưới như bạn từng biết. Với tâm thế cẩn thận, thử lại nhiều lần, bạn nghĩ rằng debugger bị hư, hoặc con MCU bị hư, vì nó chạy không đúng thứ tự, bạn báo cáo với mentor của bạn. Mentor của bạn  mỉm cười và nói “Chương trình của mình build với compiling option <code class="language-plaintext highlighter-rouge">-O2</code>, nó sẽ optimize code bằng cách re-order (sắp xếp lại) các instruction”, “Vậy làm sao đểu build không optimize vậy anh?”, “Ở đây chúng ta không làm thế, debug bằng assembly đi em”. WHATTT??? Assembly, ngôn ngữ tối cổ chỉ học 4 buổi trên trường đại học và bạn còn chẳng nhớ bạn đã từng học cái gì (ah, thực ra là tôi vẫn nhớ hàm <code class="language-plaintext highlighter-rouge">mov</code> để chuyển data giữa các register ?!?!!.</p>

<h2 id="khi-bạn-là-người-đầu-tiên-trong-công-ty-làm-việc-với-một-dòng-mcu-mớilạ">Khi bạn là người đầu tiên trong công ty làm việc với một dòng MCU mới/lạ.</h2>
<p><em>- Ngày XX tháng YY năm ZZZZ</em></p>

<p>Bạn được công ty giao cho một dự án mới, với những công nghệ mới nhất, con MCU và kit phát triển bạn được giao là bản prototype chỉ giành cho những partner có ký NDA (Non-Disclosure Agreement - thỏa thuận bảo mật thông tin), bạn không thấy có một theard stackoverflow hay post reddit nào nói về dòng MCU này. Và công việc của bạn khá đơn giản: “Bring-up (làm cho chạy) board này cho chạy tới hàm main”. Bạn không có gì nhiều ngoài tài liệu của dòng MCU này (bản preliminary và strictly confidential), compiler lưu hành nội bộ (và còn có nhiều limitation haha). Không có “BSP - Board Support Package”, vì bạn là người tạo ra nó. Và bạn phải bắt đầu tìm hiểu về cách con MCU này start up như nào và bạn biết rằng <code class="language-plaintext highlighter-rouge">C</code> compiler bạn đang dùng không có một cách chính thống nào để thiết lập được Stack Pointer trước khi project của bạn có thể sử dụng được chương trình viết bằng ngôn ngữ C.
Bạn tìm hiểu cách viết chương trình bằng assembly, và bạn ước bạn đã học assembly kỹ hơn, bạn thấy mọi thứ được dạy trên trường đại học thật là hợp lý. Bạn chợt ngờ ngợ hiểu ra Stack Pointer là gì, Vector Table là gì, Program counter là gì,…</p>

<h2 id="khi-bạn-có-một-project-làm-việc-với-co-processor-và-không-có-c-compiler">Khi bạn có một project làm việc với co-processor và không có C compiler.</h2>
<p><em>- Ngày XX tháng YY năm ZZZZ</em></p>

<p>What da heck? Tại sao lại không có C compiler? Tại vì co-processor này dành ứng dụng ngách (niche), ai lại bỏ công sức tạo ra một C compiler mà dùng cho tập khách hàng nhỏ nhỉ? Đó chỉ chỉ đơn giản là lý do liên quan đến cost. Lúc này, bạn thấy rằng chẳng có gì khó khăn cả, bạn thoải với việc viết cả một chương trình lớn bằng assembly. Bạn bẻ tay, đứng dậy vặn người và ngồi xuống đọc tài liệu ISA của co-processor (ISA - Instruction Set Architecture - Kiến trúc tập lệnh), YOLO.</p>

<h2 id="bạn-gặp-exception">Bạn gặp exception.</h2>
<p><em>- Ngày XX tháng YY năm ZZZZ</em></p>

<p>Đôi khi, bạn thấy chương trình của bạn gây ra exception (exception là một dạng interrupt - ngắn- nhưng thường gây ra bởi lỗi của CPU, ví dụ như access (truy cập) địa chỉ không tồn tại), và bạn không hiểu tại sao, chương trình của bạn nhìn khá logic. Nhưng khi debug assembly, bạn nhận ra rằng bằng cách nào đó, mỗi khi chương trình của bạn gọi đến một instrucion cụ thể, sau đó bạn dùng debugger để stepping thì bạn thấy CPU gây ra exception liên quan đến memory. Bạn nhìn các CPU register và các thông tin về mã lỗi và nhận ra rằng instruction của bạn truy cập vào “non-aligment” memory address. Voila, đây là lúc bạn đã hiểu việc học/đọc/hiểu ngôn ngữ ASSEMBLY có ích thế nào. Một khi bạn hiểu được nguyên nhân gây ra vấn đề (root cause), việc sửa lỗi trở nên dễ như ăn bánh.</p>

<h1 id="lời-kết">Lời kết,</h1>
<p>4 tình huống tôi kể trên là tình huống giả định về một kỹ sư (in general) gặp những hoàn cảnh cần kiến thức về assembly trong công việc, từ lúc là junior, qua mid level, cho đến lúc là “hardcore” engineer. Chắc chắn rằng việc nhớ toàn bộ các câu lệnh hợp ngữ có thể không cần thiết ở thời điểm tôi viết bài viết này, nhưng việc nắm được cách đọc và hiểu assembly sẽ giúp chúng ta rất nhiều trong việc debug và làm việc với low level software, và chắc chắn rằng không gì có thể ngăn cản bạn thiết kế ra chương trình cho bất kể MCU nào.</p>

<h2 id="một-số-gợi-ý-cách-tiếp-cận-ngôn-ngữ-assembly">Một số gợi ý cách tiếp cận ngôn ngữ assembly</h2>
<ul>
  <li>Build-from-scratch một project với bất kỳ evaluation kit nào bạn đang có. Giả sử bạn chỉ có toolchain (compiler, assembler, linker), bạn thử build một project “hello word” như blink led. Bạn thử tập viết startup code, viết linker script,…</li>
  <li>Thử thiết kế và viết một RTOS đơn giản.</li>
  <li>Viết một chương trình xuất xung PWM bằng assembly.</li>
</ul>

<h2 id="một-vài-link-tham-khảo-các-khái-niệm-trong-bài-viết">Một vài link tham khảo các khái niệm trong bài viết</h2>
<ul>
  <li><a href="https://en.wikipedia.org/wiki/Memory_ordering">Memory reordering - Wikipedia</a></li>
  <li><a href="https://www.felixcloutier.com/documents/gcc-asm.html">GCC assembly syntax</a></li>
  <li><a href="https://interrupt.memfault.com/blog/arm-cortex-m-exceptions-and-nvic">ARM Cortex M exception Handling - Memfault</a></li>
</ul>

<p>–</p>]]></content><author><name>Truong</name></author><category term="Engineering" /><category term="Vietnamese" /><summary type="html"><![CDATA[Info Notice: Đây là bài viết đầu tiên tôi viết bằng tiếng Việt với mong muốn bài viết này đến được với nhiều đọc giả còn đang là sinh viên hoặc những kỹ sư trẻ đang làm ngành phần mềm nhúng. Bài viết này dựa trên bài viết EABI - Why any embedded software engineer should know about it.. Mặc dù tôi đã cố gắng sử dụng nhiều từ vựng tiếng Việt nhất có thể, nhưng vì giới hạn của từ tiếng Việt đối với từ ngữ chuyên ngành nên tôi sẽ dùng từ ngữ tiếng Anh thay thế để cho giọng văn nghe sẽ tự nhiên với người đọc là những người làm kỹ sư hơn. .]]></summary></entry><entry><title type="html">Learning haskell diary (day #7). Cabal and testing setup</title><link href="/engineering/Haskell-learning-diary-d7/" rel="alternate" type="text/html" title="Learning haskell diary (day #7). Cabal and testing setup" /><published>2023-12-31T00:00:00+00:00</published><updated>2023-12-31T00:00:00+00:00</updated><id>/engineering/Haskell-learning-diary-d7</id><content type="html" xml:base="/engineering/Haskell-learning-diary-d7/"><![CDATA[<p>I was busy this year, so my Haskell learning is slowing down abit, but is not a big deal, I have my whole life to learn it. Actually, I am still practicing haskell, with the application to manipulate the hex file. It seems the project expands a bit so I think of the right way to handle it instead of using the traditional make file. So I am writng about cabal in this post.</p>
<h1 id="cabal">Cabal</h1>
<h2 id="installation-and-setup">Installation and setup</h2>
<p>There are plenty ways to install Cabal, I prefer using WSL as a platform to learn Haskell, so it seems I have the cabal installed (possibly via ghcup), so it’s time to update it.</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">&gt;</span> cabal <span class="nb">install </span>cabal-install
</code></pre></div></div>
<p>Then go to the project folder and initialize</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">&gt;</span> <span class="nb">mkdir </span>project_dir <span class="o">&amp;&amp;</span> <span class="nb">cd </span>project_dir
<span class="o">&gt;</span> cabal init
</code></pre></div></div>
<p>After this command, the <code class="language-plaintext highlighter-rouge">project_dir.cabal</code> file will be created, we will edit our build structure in this file.</p>
<h2 id="setup-project-with-cabal">Setup project with Cabal</h2>
<p>At the directory of the cabal file:
to build then run:</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">&gt;</span> cabal build
<span class="o">&gt;</span> cabal run
</code></pre></div></div>
<p>The cabal package is written in haskell, and it is consider as a part of the haskell ecosystem. With cabal, the source code will be more organized, just like how we use make for the other project. I put here the the cabal file of the project I am working on for the sake of explanation.</p>
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">cabal</span><span class="o">-</span><span class="n">version</span><span class="o">:</span>       <span class="o">&gt;=</span><span class="mf">1.8</span><span class="o">.</span><span class="mf">0.4</span>
<span class="c1">-- Initial package description 'thingkell.cabal' generated by 'cabal init'.</span>
<span class="c1">--   For further documentation, see http://haskell.org/cabal/users-guide/</span>

<span class="n">name</span><span class="o">:</span>                <span class="n">thingkell</span>
<span class="n">version</span><span class="o">:</span>             <span class="mf">0.1</span><span class="o">.</span><span class="mf">0.0</span>
<span class="c1">-- synopsis:</span>
<span class="c1">-- description:</span>
<span class="c1">-- bug-reports:</span>
<span class="c1">-- license:</span>
<span class="n">license</span><span class="o">-</span><span class="n">file</span><span class="o">:</span>        <span class="kt">LICENSE</span>
<span class="n">author</span><span class="o">:</span>              <span class="kt">Truong</span> <span class="kt">Tran</span>
<span class="n">maintainer</span><span class="o">:</span>          <span class="n">contact</span><span class="o">@</span><span class="n">tranvantruong</span><span class="o">.</span><span class="n">com</span>
<span class="c1">-- copyright:</span>
<span class="c1">-- category:</span>
<span class="n">build</span><span class="o">-</span><span class="kr">type</span><span class="o">:</span>          <span class="kt">Simple</span>
<span class="n">extra</span><span class="o">-</span><span class="n">source</span><span class="o">-</span><span class="n">files</span><span class="o">:</span>  <span class="kt">CHANGELOG</span><span class="o">.</span><span class="n">md</span><span class="p">,</span> <span class="kt">README</span><span class="o">.</span><span class="n">md</span><span class="p">,</span> <span class="n">bit_utils</span><span class="o">.</span><span class="n">c</span>
<span class="n">executable</span> <span class="n">thingkell</span>
  <span class="n">main</span><span class="o">-</span><span class="n">is</span><span class="o">:</span>             <span class="kt">Main</span><span class="o">.</span><span class="n">hs</span>
  <span class="n">other</span><span class="o">-</span><span class="n">modules</span><span class="o">:</span>   <span class="kt">Memkell</span><span class="p">,</span> <span class="kt">Bitkell</span><span class="p">,</span> <span class="kt">Crkell</span><span class="p">,</span> <span class="kt">Hexkell</span><span class="p">,</span> <span class="kt">Ihex</span><span class="p">,</span> <span class="kt">Ffi</span>
  <span class="c1">-- other-extensions:</span>
  <span class="n">build</span><span class="o">-</span><span class="n">depends</span><span class="o">:</span>       <span class="n">base</span> <span class="o">&gt;=</span><span class="mf">4.13</span> <span class="o">&amp;&amp;</span> <span class="o">&lt;</span><span class="mf">4.14</span><span class="p">,</span>
                      <span class="n">split</span><span class="p">,</span>
                      <span class="n">parallel</span><span class="p">,</span>
                      <span class="n">bytestring</span><span class="p">,</span>
                      <span class="n">attoparsec</span><span class="p">,</span>
                      <span class="n">optparse</span><span class="o">-</span><span class="n">applicative</span>
  <span class="n">hs</span><span class="o">-</span><span class="n">source</span><span class="o">-</span><span class="n">dirs</span><span class="o">:</span> <span class="o">./</span><span class="n">src</span>
  <span class="c1">-- extra-source-file: src/bit_utils.c</span>
  <span class="c1">--C-sources-dirs: ./src</span>
  <span class="kt">C</span><span class="o">-</span><span class="n">sources</span><span class="o">:</span> <span class="n">src</span><span class="o">/</span><span class="n">bit_utils</span><span class="o">.</span><span class="n">c</span>
  <span class="kt">Includes</span><span class="o">:</span> <span class="n">bit_utils</span><span class="o">.</span><span class="n">h</span>
  <span class="kt">Include</span><span class="o">-</span><span class="n">dirs</span><span class="o">:</span> <span class="o">./</span><span class="n">src</span>
  <span class="kt">Install</span><span class="o">-</span><span class="n">includes</span><span class="o">:</span> <span class="n">bit_utils</span><span class="o">.</span><span class="n">h</span>
  <span class="kr">default</span><span class="o">-</span><span class="n">language</span><span class="o">:</span>    <span class="kt">Haskell2010</span>

</code></pre></div></div>

<p>What I want to point out here is how to setup this to work with mixed <strong>C</strong> source code via FFI with haskell.</p>
<h2 id="setup-testing-in-cabal">Setup testing in Cabal</h2>
<p>Yeah, why not leveraging the test driven development, and why not apply it from the begining. It seems testing setup in cabal is nothing more than just a separated executable file that has the test harness to the code we want to test. At the time of wrtting this blog post, I have the following folder structure of how I setup the test code for my module.
I use the Tasty frame work to develop test, the test case organizing is intuitive, so which this setup, I can focusing on develop the test case case and run the test every time I modify the code. It worths noting that testing is all about checking the side effect, so we should prepare testing is a way that can be easily resued when we change the interal processing implementation which is normally pure.</p>

<p>I think for now, we have all the <strong>CABAL</strong> setup necessary for a complete <strong><code class="language-plaintext highlighter-rouge">Haskell</code></strong> project including the following steps:</p>
<ul>
  <li>The haskell source code itself for the logic code.</li>
  <li>The C code and Foregin Function Interface (FFI) setup</li>
  <li>The Tasty test framework setup.</li>
</ul>

<p>Actually, setting up the testing with CABAL is nothing like setting up the whole project target. except that instead of calling the <code class="language-plaintext highlighter-rouge">cabal run</code>, we shall call <code class="language-plaintext highlighter-rouge">cabal test</code>. I took a while to realize that and come up with the following folder structure to setup the project with the testing.</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>prj_root_folder
¦   thingkell.cabal
+---app
+---output
+---src
¦       Bitkell.hs
¦       bit_utils.c
¦       bit_utils.h
¦       Crkell.hs
¦       Ffi.hs
¦       Hexkell.hs
¦       Ihex.hs
¦       Main.hs
¦       Memkell.hs
¦       MemService.hs
¦       
+---test
        8byte.bin
        8byte_start0.hex
        8byte_start17.hex
        8byte_startFFFC.hex
        HexTest.hs
        Long_Lorem_ipsum_start_at_32K.bin
        Long_Lorem_ipsum_start_at_7FF0.hex
        Long_Lorem_ipsum_start_at_7FF0_variance1.hex
        Main.hs
</code></pre></div></div>

<p>We can see that I have put all the core implementation inside the <code class="language-plaintext highlighter-rouge">src</code> folder, while the test artifact into the <code class="language-plaintext highlighter-rouge">test</code>folder. You will see that each folder has it own main.hs, which means that we have 2  targets in the cabal file and each one need their own main function to run.</p>
<h1 id="testing-with-tasty">Testing with <code class="language-plaintext highlighter-rouge">tasty</code></h1>
<p>Then, we have finish setup the testing environment. Then, we will jump down to actually writing the test. OK, I approached the topic by desigining the test case firstly, from simple to sophisticated. I have preprapred some known-good hex file using the available hex file utility. I have tried to create several use case to vet all code I wrote in the core implementation, something like to test my logic to handle different type of hex record, such as data record, linear address record,… I put here some of the testing code I wrote in the <code class="language-plaintext highlighter-rouge">HexTest.hs</code> below (it is just a part of it).</p>

<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">test_CollectAndMergeMemSect</span> <span class="o">::</span> <span class="kt">TestTree</span>
<span class="n">test_CollectAndMergeMemSect</span> <span class="o">=</span> <span class="n">testCase</span> <span class="s">"Test collect and merge memsect"</span> <span class="o">$</span> <span class="kr">do</span>
    <span class="kr">let</span> <span class="n">hexRecord</span> <span class="o">=</span> <span class="p">[</span><span class="kt">IntelHexRecord</span> <span class="p">{</span><span class="n">ihexAddress</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span> <span class="n">ihexData</span> <span class="o">=</span> <span class="kt">[]</span><span class="p">,</span> <span class="n">ihexRecordType</span> <span class="o">=</span> <span class="mi">4</span><span class="p">},</span>
            <span class="kt">IntelHexRecord</span> <span class="p">{</span><span class="n">ihexAddress</span> <span class="o">=</span> <span class="mi">4</span><span class="p">,</span> <span class="n">ihexData</span> <span class="o">=</span> <span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">ihexRecordType</span> <span class="o">=</span> <span class="mi">0</span><span class="p">},</span>
            <span class="kt">IntelHexRecord</span> <span class="p">{</span><span class="n">ihexAddress</span> <span class="o">=</span> <span class="mi">6</span><span class="p">,</span> <span class="n">ihexData</span> <span class="o">=</span> <span class="p">[</span><span class="mi">2</span><span class="p">],</span> <span class="n">ihexRecordType</span> <span class="o">=</span> <span class="mi">0</span><span class="p">}</span>
            <span class="p">]</span>
    <span class="n">print</span> <span class="o">$</span> <span class="n">collectAndMerge2Memsect</span> <span class="n">hexRecord</span>

<span class="n">test_ihex2MemSect</span> <span class="o">::</span> <span class="kt">TestTree</span>
<span class="n">test_ihex2MemSect</span> <span class="o">=</span> <span class="n">testCase</span> <span class="s">"Convert hex file into MemSect"</span> <span class="o">$</span> <span class="kr">do</span>
    <span class="c1">-- test</span>
    <span class="n">ihRecord</span> <span class="o">&lt;-</span> <span class="n">iHex2HexRecords</span> <span class="s">"test/8byte_start17.hex"</span>
    <span class="kr">let</span> <span class="n">preprocess</span> <span class="o">=</span> <span class="n">hexRecordPrependExtended</span> <span class="o">$</span> <span class="n">catMaybes</span> <span class="n">ihRecord</span>
    <span class="n">print</span> <span class="o">$</span> <span class="n">hexChunks2MemSect</span> <span class="n">preprocess</span>

<span class="n">test_ihex2MemSect_fffc</span> <span class="o">::</span> <span class="kt">TestTree</span>
<span class="n">test_ihex2MemSect_fffc</span> <span class="o">=</span> <span class="n">testCase</span> <span class="s">"Convert hex file that crosses"</span> <span class="o">$</span> <span class="kr">do</span>
    <span class="c1">-- test</span>
    <span class="n">ihRecord</span> <span class="o">&lt;-</span> <span class="n">iHex2HexRecords</span> <span class="s">"test/8byte_startFFFC.hex"</span>
    <span class="kr">let</span> <span class="n">preprocess</span> <span class="o">=</span> <span class="n">hexRecordPrependExtended</span> <span class="o">$</span> <span class="n">catMaybes</span> <span class="n">ihRecord</span>
    <span class="n">print</span> <span class="o">$</span> <span class="n">hexChunks2MemSect</span> <span class="n">preprocess</span>
</code></pre></div></div>

<p>Well thanks to this testing, I help me to detect the problem in my code easier, I am glad that the effort figuring out the setup worths.</p>

<p>I will finish this blog at this time, I have some incorrect logic to debug so I will make the report next time about the project I am working on.
See you and Happy new year!</p>]]></content><author><name>Truong</name></author><category term="Engineering" /><category term="Learning" /><category term="Haskell" /><category term="cabal" /><summary type="html"><![CDATA[I was busy this year, so my Haskell learning is slowing down abit, but is not a big deal, I have my whole life to learn it. Actually, I am still practicing haskell, with the application to manipulate the hex file. It seems the project expands a bit so I think of the right way to handle it instead of using the traditional make file. So I am writng about cabal in this post. Cabal Installation and setup There are plenty ways to install Cabal, I prefer using WSL as a platform to learn Haskell, so it seems I have the cabal installed (possibly via ghcup), so it’s time to update it. &gt; cabal install cabal-install Then go to the project folder and initialize &gt; mkdir project_dir &amp;&amp; cd project_dir &gt; cabal init After this command, the project_dir.cabal file will be created, we will edit our build structure in this file. Setup project with Cabal At the directory of the cabal file: to build then run: &gt; cabal build &gt; cabal run The cabal package is written in haskell, and it is consider as a part of the haskell ecosystem. With cabal, the source code will be more organized, just like how we use make for the other project. I put here the the cabal file of the project I am working on for the sake of explanation. cabal-version: &gt;=1.8.0.4 -- Initial package description 'thingkell.cabal' generated by 'cabal init'. -- For further documentation, see http://haskell.org/cabal/users-guide/ name: thingkell version: 0.1.0.0 -- synopsis: -- description: -- bug-reports: -- license: license-file: LICENSE author: Truong Tran maintainer: contact@tranvantruong.com -- copyright: -- category: build-type: Simple extra-source-files: CHANGELOG.md, README.md, bit_utils.c executable thingkell main-is: Main.hs other-modules: Memkell, Bitkell, Crkell, Hexkell, Ihex, Ffi -- other-extensions: build-depends: base &gt;=4.13 &amp;&amp; &lt;4.14, split, parallel, bytestring, attoparsec, optparse-applicative hs-source-dirs: ./src -- extra-source-file: src/bit_utils.c --C-sources-dirs: ./src C-sources: src/bit_utils.c Includes: bit_utils.h Include-dirs: ./src Install-includes: bit_utils.h default-language: Haskell2010 What I want to point out here is how to setup this to work with mixed C source code via FFI with haskell. Setup testing in Cabal Yeah, why not leveraging the test driven development, and why not apply it from the begining. It seems testing setup in cabal is nothing more than just a separated executable file that has the test harness to the code we want to test. At the time of wrtting this blog post, I have the following folder structure of how I setup the test code for my module. I use the Tasty frame work to develop test, the test case organizing is intuitive, so which this setup, I can focusing on develop the test case case and run the test every time I modify the code. It worths noting that testing is all about checking the side effect, so we should prepare testing is a way that can be easily resued when we change the interal processing implementation which is normally pure. I think for now, we have all the CABAL setup necessary for a complete Haskell project including the following steps: The haskell source code itself for the logic code. The C code and Foregin Function Interface (FFI) setup The Tasty test framework setup. Actually, setting up the testing with CABAL is nothing like setting up the whole project target. except that instead of calling the cabal run, we shall call cabal test. I took a while to realize that and come up with the following folder structure to setup the project with the testing. prj_root_folder ¦ thingkell.cabal +---app +---output +---src ¦ Bitkell.hs ¦ bit_utils.c ¦ bit_utils.h ¦ Crkell.hs ¦ Ffi.hs ¦ Hexkell.hs ¦ Ihex.hs ¦ Main.hs ¦ Memkell.hs ¦ MemService.hs ¦ +---test 8byte.bin 8byte_start0.hex 8byte_start17.hex 8byte_startFFFC.hex HexTest.hs Long_Lorem_ipsum_start_at_32K.bin Long_Lorem_ipsum_start_at_7FF0.hex Long_Lorem_ipsum_start_at_7FF0_variance1.hex Main.hs We can see that I have put all the core implementation inside the src folder, while the test artifact into the testfolder. You will see that each folder has it own main.hs, which means that we have 2 targets in the cabal file and each one need their own main function to run. Testing with tasty Then, we have finish setup the testing environment. Then, we will jump down to actually writing the test. OK, I approached the topic by desigining the test case firstly, from simple to sophisticated. I have preprapred some known-good hex file using the available hex file utility. I have tried to create several use case to vet all code I wrote in the core implementation, something like to test my logic to handle different type of hex record, such as data record, linear address record,… I put here some of the testing code I wrote in the HexTest.hs below (it is just a part of it). test_CollectAndMergeMemSect :: TestTree test_CollectAndMergeMemSect = testCase "Test collect and merge memsect" $ do let hexRecord = [IntelHexRecord {ihexAddress = 0, ihexData = [], ihexRecordType = 4}, IntelHexRecord {ihexAddress = 4, ihexData = [1], ihexRecordType = 0}, IntelHexRecord {ihexAddress = 6, ihexData = [2], ihexRecordType = 0} ] print $ collectAndMerge2Memsect hexRecord test_ihex2MemSect :: TestTree test_ihex2MemSect = testCase "Convert hex file into MemSect" $ do -- test ihRecord &lt;- iHex2HexRecords "test/8byte_start17.hex" let preprocess = hexRecordPrependExtended $ catMaybes ihRecord print $ hexChunks2MemSect preprocess test_ihex2MemSect_fffc :: TestTree test_ihex2MemSect_fffc = testCase "Convert hex file that crosses" $ do -- test ihRecord &lt;- iHex2HexRecords "test/8byte_startFFFC.hex" let preprocess = hexRecordPrependExtended $ catMaybes ihRecord print $ hexChunks2MemSect preprocess Well thanks to this testing, I help me to detect the problem in my code easier, I am glad that the effort figuring out the setup worths. I will finish this blog at this time, I have some incorrect logic to debug so I will make the report next time about the project I am working on. See you and Happy new year!]]></summary></entry><entry><title type="html">Hex Calculator (still not finished)</title><link href="/tools/hexcalc" rel="alternate" type="text/html" title="Hex Calculator (still not finished)" /><published>2023-09-24T00:00:00+00:00</published><updated>2023-09-24T00:00:00+00:00</updated><id>/tools/hex-calc</id><content type="html" xml:base="/tools/hexcalc"><![CDATA[<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/mathjs/11.11.1/math.js" integrity="sha512-PSHSbngD/Hc1zYbMeM4xUMRt+gD8x7xYdZaDqRE8iy1oDu94O2Mqi2WqYe8QWji50+4EFBbp/Opwc+Nl+ruaqw==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" />
      </head>
<div class="center noselect" style="margin: 1px;" id="calculator">
    <div id="outputs">
    <textarea class="noselect output" readonly="" id="output" rows="4" style="font-family: 'Courier New', monospace;"></textarea>
    <textarea class="noselect output" readonly="" id="output2" rows="4" style="font-family: 'Courier New', monospace;"></textarea>
    <textarea class="noselect output" readonly="" id="outputr" rows="4" style="font-family: 'Courier New', monospace;"></textarea>
    </div>
    <div id="buttons">
        <button class="button-alpha" onclick="appendHEXToGlobalString('D')" id="btnD ">D</button>
        <button class="button-alpha" onclick="appendHEXToGlobalString('E')" id="btnE ">E</button>
        <button class="button-alpha" onclick="appendHEXToGlobalString('F')" id="btnF">F</button>
        <button class="button btn-operational" onclick="Clear_input()" id="btnClr">Clear</button>
        <button class="button-alpha" onclick="appendHEXToGlobalString('A')" id="btnA ">A</button>
        <button class="button-alpha" onclick="appendHEXToGlobalString('B')" id="btnB ">B</button>
        <button class="button-alpha" onclick="appendHEXToGlobalString('C')" id="btnC ">C</button>
        <button class="button btn-operational" onclick="BackSpace()" id="btnBkS">⌫</button>
        <button class="button" onclick="appendToGlobalString('7')" id="btn7 ">7</button>
        <button class="button" onclick="appendToGlobalString('8')" id="btn8 ">8</button>
        <button class="button" onclick="appendToGlobalString('9')" id="btn9 ">9</button>
        <button class="button button-op" onclick="appendOperator('+')" id="btnAdd">+</button>
        <button class="button" onclick="appendToGlobalString('4')" id="btn4 ">4</button>
        <button class="button" onclick="appendToGlobalString('5')" id="btn5 ">5</button>
        <button class="button" onclick="appendToGlobalString('6')" id="btn6 ">6</button>
        <button class="button button-op" onclick="appendOperator('-')" id="btnSubtract">-</button>
        <button class="button" onclick="appendToGlobalString('1')" id="btn1">1</button>
        <button class="button" onclick="appendToGlobalString('2')" id="btn2 ">2</button>
        <button class="button" onclick="appendToGlobalString('3')" id="btn3 ">3</button>
        <button class="button button-op" onclick="appendOperator('*')" id="btnMultiply">×</button>
        <button class="button" onclick="appendToGlobalString('0')" id="zero">0</button>
        <button class="button" onclick="toggleDec()" id="btnDec">DEC</button>
        <button class="button" onclick="toggleHex()" id="btnHex">HEX</button>
        <!-- Add buttons for other digits and operations -->
        <button class="button button-op" onclick="ToggleRPN()" id="btnSign">+/-</button>
        <button class="button btn-operational" onclick="ToggleRPN()" id="btnRPN">RPN</button>
        <button class="button button-op" onclick="appendOperator('&amp;')" id="btnAnd">AND</button>
        <button class="button button-op" onclick="appendOperator('|')" id="btnOr">OR</button>
        <button class="button button-op" onclick="appendOperator('&gt;&gt;')" id="btnShR">&gt;&gt;</button>
        <button class="button" onclick="Calculate()" id="btnEquals">=</button>
        <button class="button button-op" onclick="appendOperator('^')" id="btnXor">XOR</button>
        <button class="button button-op" onclick="appendOperator('~')" id="btnNot">NOT</button>
        <button class="button button-op" onclick="appendOperator('&lt;&lt;')" id="btnShL">&lt;&lt;</button>
    </div>
</div>

<style>

.lock-screen {
    height: 100%;
    overflow: hidden;
    width: 100%;
    position: fixed;
}

.center {
  border: 1 solid;
  margin: auto;
  width: 50%;
  padding: 1px;
}

  .noselect {
  -webkit-touch-callout: none; /* iOS Safari */
    -webkit-user-select: none; /* Safari */
     -khtml-user-select: none; /* Konqueror HTML */
       -moz-user-select: none; /* Old versions of Firefox */
        -ms-user-select: none; /* Internet Explorer/Edge */
            user-select: none; /* Non-prefixed version, currently
                                  supported by Chrome, Edge, Opera and Firefox */
}

  * {
      touch-action: manipulation;
  }

#calculator {
    touch-action: manipulation;
    width: 95%;
    margin: 0 auto;
    padding: 0px;
    border: 1px solid #ccc;
    background-color: #f0f0f0;
    user-select: none;
}

#outputs {
    background-color: white;
    resize: none;
    user-select: none;
    user-select: none;
}

.output {
    height: 1em;
    width: 99%;
    font-size: 24px;
    font-family: 'Courier New', monospace;
    text-align: right;
    padding: 3px;
    background-color: white;
    border: 1px solid #FFF;
    resize: none;
    user-select: none;
}

#buttons {
    width: auto;
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    grid-gap: 3px;
}

.button {
    font-size: 25px;
    padding: 5px;
    background-color: #333;
    color: white;
    border: none;
    cursor: pointer;
    width: 20%
    font-size: 20px;
    padding-bottom: 10%;
  -webkit-touch-callout: none; /* iOS Safari */
    -webkit-user-select: none; /* Safari */
     -khtml-user-select: none; /* Konqueror HTML */
       -moz-user-select: none; /* Old versions of Firefox */
        -ms-user-select: none; /* Internet Explorer/Edge */
            user-select: none; /* Non-prefixed version, currently
                                  supported by Chrome, Edge, Opera and Firefox */
}

.button-op {
    padding: 5px;
    background-color: #5bc0de;
    color: white;
    border: none;
    cursor: pointer;
    width: 20%
    font-size: 20px;
    padding-bottom: 10%;
  -webkit-touch-callout: none; /* iOS Safari */
    -webkit-user-select: none; /* Safari */
     -khtml-user-select: none; /* Konqueror HTML */
       -moz-user-select: none; /* Old versions of Firefox */
        -ms-user-select: none; /* Internet Explorer/Edge */
            user-select: none; /* Non-prefixed version, currently
                                  supported by Chrome, Edge, Opera and Firefox */
}

.button-alpha {
    font-size: 20px;
    padding: 10px;
    background-color: #42f578;
    color: white;
    border: none;
    cursor: pointer;
    width: 20%
    padding-bottom: 10%;
  -webkit-touch-callout: none; /* iOS Safari */
    -webkit-user-select: none; /* Safari */
     -khtml-user-select: none; /* Konqueror HTML */
       -moz-user-select: none; /* Old versions of Firefox */
        -ms-user-select: none; /* Internet Explorer/Edge */
            user-select: none; /* Non-prefixed version, currently
                                  supported by Chrome, Edge, Opera and Firefox */
}

.button:active {
    border: none;
    background-color: #EB2; /* Change this color to the desired active color */
}

.button-alpha:active {
    border: none;
    background-color: #EB2; /* Change this color to the desired active color */
}

/* Style the "0" button to span two columns */
#zero {
    grid-column: span 2; /* Span 2 columns */
    grid-row: span 2; /* Span 2 columns */
}

#btnEquals {
    grid-row: span 2; /* Span 2 columns */
    background-color: #d9534f; /* Change this color to the desired active color */
}

.btn-operational {
    background-color: #d9534f; /* Change this color to the desired active color */
}

#btnEquals:active {
    grid-row: span 2; /* Span 2 columns */
    background-color: #EB2; /* Change this color to the desired active color */
}
/* Add more specific styling as needed */

    /* Add other CSS rules for styling */
</style>

<script>
let input_eq_str='';
let result='';
let mode_radix = 'HEX';
let mode_input = 'infix';
let arg1=''
let arg2=''
let operator=''
let result_string=''
// ARG1, ARG2 and OP(operator)
let calc_state = "INIT";

// Get references to the buttons and output element
const hexButton = document.getElementById('btnHex');
const decButton = document.getElementById('btnDec');

const outputElement = document.getElementById("output");
const output2oprand = document.getElementById("output2");
const outputresult = document.getElementById("outputr");

toggleHex();
setCalculatorMode(mode_radix);
outputElement.value ="Welcome to"
output2oprand.value ="hex calculator!"
outputresult.value ="Enjoy your calculation!"

const hexToDecimal = (hexString) => parseInt(hexString, 16).toString();
const decimalToHex = (decimalString) => parseInt(decimalString, 10).toString(16).toUpperCase();



//-- pattern to check if the input is within number
const hexPattern = /^[0-9A-Fa-f]$/;

//const math = require('mathjs'); // If you're using Node.js


function nop(){
}

function toggleHex()
{
    if(mode_radix==='DEC')
    {
        mode_radix='HEX';
        
        /* Covert envery thing to DEC */
        if( arg1!=='') {arg1=decimalToHex(arg1);}
        if( arg2!=='') {arg2=decimalToHex(arg2);}
        if( result_string!=='') {result_string=decimalToHex(result_string);}
        
        setCalculatorMode(mode_radix);
        if(calc_state!=='INIT')
        {
            update_display();
        }
    }
}

function toggleDec()
{
    if(mode_radix==='HEX')
    {
        mode_radix='DEC';
        
        /* Covert envery thing to DEC */
        if( arg1!=='') {arg1=hexToDecimal(arg1);}
        if( arg2!=='') {arg2=hexToDecimal(arg2);}
        if( result_string!=='') {result_string=hexToDecimal(result_string);}
        
        setCalculatorMode(mode_radix);
        update_display();
    }
}

// Function to append a letter to the global string
function appendToGlobalString(letter) {
    if(calc_state==='ARG1')
    {
        /* If this is still in the state of inputing ARG1 or ARG2, then appen letter */
        arg1 += letter;
    }
    else if(calc_state==='ARG2')
    {
        arg2 += letter;
    }
    else
    {
        if(calc_state==='OP')
        {
            //- if the current state is OP, then switch to ARG2
            calc_state='ARG2';
            arg2 = ''
            arg2 += letter;
            
        } else 
        {
            calc_state='ARG1';
            arg1 = ''
            arg1 += letter;
        }
        
    }
    update_display();
}

// Function to append a letter to the global string
function appendHEXToGlobalString(letter) {
    if(mode_radix==='HEX')    {
        if(calc_state==='ARG1')
        {
            /* If this is still in the state of inputing ARG1 or ARG2, then appen letter */
            arg1 += letter;
        }
        else if(calc_state==='ARG2')
        {
            arg2 += letter;
        }
        else
        {
            if(calc_state==='OP')
            {
                //- if the current state is OP, then switch to ARG2
                calc_state='ARG2';
                arg2 = ''
                arg2 += letter;
                
            } else 
            {
                calc_state='ARG1';
                arg1 = ''
                arg1 += letter;
            }
            
        }
        update_display();
    }
}

// Function to append a letter to the global string
function appendOperator(letter) {
    if(calc_state==='ARG1')
    {
        // If current state is arg1, then change to the OP
        calc_state='OP';
        if(arg1===''){arg1='0';}
        operator = letter;
    } else if(calc_state==='OP')
    {
        operator = letter;
    }
    else if(calc_state ==='EQ')
    {
        /* if it is already in the EQ, then update the result string to the first argument */
        arg1=result_string;
        operator = letter;
        arg2='';
        result_string='';
        calc_state='OP';
    }
    update_display();
}

function insertSpaces(str) {
    // Use regular expression to insert a space every 4 characters from the end
    return str.split('').reverse().join('').replace(/(.{4})(?=.)/g, '$1 ').split('').reverse().join('');
}

function update_display(){
    let suffix=''
    if( mode_radix === 'HEX')
    {
        suffix=' h'
        if(arg1 ==='')
        {
            outputElement.value = '';
        }
        else
        {
            outputElement.value = insertSpaces(arg1) + suffix;
        }
        
        if(arg2 ==='')
        {
            output2oprand.value = operator;
        }
        else
        {
            output2oprand.value = operator + ' ' + insertSpaces(arg2) +suffix;
        }
        
        if(result_string ==='')
        {
            outputresult.value =result_string;
        }
        else
        {
            outputresult.value = '= '+ insertSpaces(result_string) + suffix;
        }
    }
    else
    {
        suffix=''
        if(arg1 ==='')
        {
            outputElement.value = arg1;
        }
        else
        {
            outputElement.value = arg1 + suffix;
        }
        
        if(arg2 ==='')
        {
            output2oprand.value = operator;
        }
        else
        {
            output2oprand.value = operator + ' ' + arg2 +suffix;
        }
        
        if(result_string ==='')
        {
            outputresult.value =result_string;
        }
        else
        {
            outputresult.value = '= '+ result_string + suffix;
        }
    }
}

function Calculate(){
    if(calc_state ==='EQ')
    {
        /* if it is already in the EQ, then update the result string to the first argument */
        arg1=result_string;
    }
    else
    {
        /* if it is not from the calculation phase */
        calc_state = 'EQ';
    }
    Evaluate_Expression();
}

function custom_XOR(a,b)
{
    return (parseInt(a, 10) ^ parseInt(b, 10));
}

function Evaluate_Expression()
{
    try {
        let temp_arg1='';
        let temp_arg2='';
        let temp_res='';
        let temp_op='';
        if( mode_radix==='HEX')
        {
            if(arg1!==''){   temp_arg1 = hexToDecimal(arg1); } 
            if(arg2!==''){      temp_arg2 = hexToDecimal(arg2);}
        }
        else
        {
            temp_arg1=arg1;
            temp_arg2=arg2;
        }
        // Evaluate the expression using Math.js
        input_eq_str = arg1 + operator + arg2;
        if(operator==='^')  {
            // Math js does not support XOR so do it ourself
            temp_res = custom_XOR(temp_arg1,temp_arg2);
        }else
        {
            //temp_res = math.evaluate(temp_arg1 + operator + temp_arg2);
            if( operator==='<<' )    { temp_op='<<';}
            else if ( operator==='>>' )    { temp_op='>>>';}
            else {temp_op = operator;}
            temp_res = eval(temp_arg1 + temp_op + temp_arg2);
        }
        
        if( mode_radix==='HEX')
        {
            result_string = decimalToHex(temp_res);
        }
        else
        {
            result_string= temp_res;
        }

        update_display();
        
    } catch (error) {
        console.error('Error:', error.message);
        outputElement.value = error.message;
    }
}

function Clear_input(){
    arg1='';
    operator='';
    arg2='';
    result_string='';
    calc_state="ARG1";
    update_display();
}

function BackSpace(){
    if( calc_state==='ARG1')
    {
        if (arg1.length > 0) {
            // Remove the last character
            arg1 = arg1.slice(0, -1);
            // Update the output
            update_display();
        }
    }
    else if( calc_state==='ARG2')  {
        if (arg2.length > 0) {
            // Remove the last character
            arg2 = arg2.slice(0, -1);
            // Update the output
            update_display();
        }
        
    }
}
// Function to set the calculator mode
function setCalculatorMode(mode) {
    if (mode_radix === 'HEX') {
        // Set HEX mode
        hexButton.style.backgroundColor = 'green';
        decButton.style.backgroundColor = ''; // Reset DEC button color
        // Enable A-F buttons
        enableHexButtons();
    } else if (mode_radix === 'DEC') {
        // Set DEC mode
        decButton.style.backgroundColor = 'green';
        hexButton.style.backgroundColor = ''; // Reset HEX button color
        // Disable A-F buttons
        disableHexButtons();
    }
}

// Function to enable A-F buttons
function enableHexButtons() {
    const hexButtons = document.querySelectorAll('.button-alpha');
    hexButtons.forEach(button => {
        //button.removeAttribute('disabled');
        button.style.backgroundColor = ''; // Reset button color
    });
}

// Function to disable A-F buttons
function disableHexButtons() {
    const hexButtons = document.querySelectorAll('.button-alpha');
    hexButtons.forEach(button => {
        //button.setAttribute('disabled', 'true');
        button.style.backgroundColor = 'grey'; // Set button color to grey
    });
}

</script>]]></content><author><name>Truong</name></author><summary type="html"><![CDATA[D E F Clear A B C ⌫ 7 8 9 + 4 5 6 - 1 2 3 × 0 DEC HEX +/- RPN AND OR &gt;&gt; = XOR NOT &lt;&lt;]]></summary></entry><entry><title type="html">SHA-256 Hash from Hex string or C Array Input</title><link href="/tools/sha256" rel="alternate" type="text/html" title="SHA-256 Hash from Hex string or C Array Input" /><published>2023-09-20T00:00:00+00:00</published><updated>2023-09-20T00:00:00+00:00</updated><id>/tools/SHA2-256-calculator</id><content type="html" xml:base="/tools/sha256"><![CDATA[<head>
    <style>
        #inputData, #outputResult {
            background-color: #9BD3FFFF; /* Change this value to your desired color */
            background-blend-mode: multiply
        }
    </style>
</head>

<p>This page hepls to calculate the SHA-256 value from the input hex string or array of uint8 values in C syntax.</p>

<div>
  <label for="inputData">Enter a hexadecimal array or C array:</label>
  <input type="text" id="inputData" />
</div>

<div>
  <label for="outputResult">Result (SHA-256 Hex):</label>
  <textarea id="outputResult" rows="4" cols="50" readonly=""></textarea>
</div>

<p><button onclick="calculateSHA256()">Calculate SHA-256</button></p>

<script>
function calculateSHA256() {
  // Get the input value
  var inputElement = document.getElementById("inputData");
  var inputData = inputElement.value;

  // Remove unnecessary characters and spaces

  // Check if the input contains curly braces (C array syntax)
  var isCArray = inputData.includes('{') && inputData.includes('}');

    if (isCArray) 
    {
        var hexString = convertDecHex(inputData)
    }
    else{

      inputData = inputData.replace(/[^0-9a-fA-F,{}\s]/g, '');
      // Convert the cleaned-up input to a hexadecimal string
      var hexArray = inputData.split(/[\s,{}]+/).filter(Boolean);
      var hexString = hexArray.join('');
    }
  // Convert the hexadecimal string to a Uint8Array
  var hexBytes = new Uint8Array(hexString.length / 2);
  for (var i = 0; i < hexString.length; i += 2) {
    hexBytes[i / 2] = parseInt(hexString.substr(i, 2), 16);
  }

  // Calculate the SHA-256 hash
  crypto.subtle.digest("SHA-256", hexBytes).then(function(hashBuffer) {
    var hashArray = Array.from(new Uint8Array(hashBuffer));
    var hashHex = hashArray.map(byte => byte.toString(16).padStart(2, '0')).join('');

    // Display the result in the output textarea
    var outputElement = document.getElementById("outputResult");
    outputElement.value = hashHex;
  }).catch(function(error) {
    console.error(error);
  });
}

function convertDecHex(inStr) {
    let parsedValues = [];
//convert str to arr str
    let aStr =  inStr.replaceAll(/[{},'\[\]]/g, " ").split(/\s+/g);
    aStr.forEach((str) => {
            if (str.length !== 0)
                str.includes('0x') ?
                    (  str.length===3? parsedValues.push(str.replace('0x', '0')):
                        parsedValues.push(str.replace('0x', '')) ):
                    (  (+str).toString(16).length===1? parsedValues.push('0'+(+str).toString(16)):
                        parsedValues.push(((+str).toString(16))))
        }
    )
    return parsedValues.join('');
}

</script>]]></content><author><name>Truong</name></author><summary type="html"><![CDATA[This page hepls to calculate the SHA-256 value from the input hex string or array of uint8 values in C syntax. Enter a hexadecimal array or C array: Result (SHA-256 Hex): Calculate SHA-256]]></summary></entry><entry><title type="html">Diffie-Hellman key exchange with color blending</title><link href="/shower%20thought/Diffie-Hellman-key-exchange-with-color/" rel="alternate" type="text/html" title="Diffie-Hellman key exchange with color blending" /><published>2023-08-15T00:00:00+00:00</published><updated>2023-08-15T00:00:00+00:00</updated><id>/shower%20thought/Diffie-Hellman-key-exchange-with-color</id><content type="html" xml:base="/shower%20thought/Diffie-Hellman-key-exchange-with-color/"><![CDATA[<p>The first time I learn about key exchange protocol, I came across an analogy of the protocol using color mixing (<a href="https://commons.wikimedia.org/wiki/File:Diffie-Hellman_Key_Exchange.svg">Wikipedia image</a>). This analogy is easy to understand, but does it actually work, ignoring the fact that it may be insecure. Let’s see now.</p>

<h1 id="diffie-hellman-problem">Diffie-Hellman problem</h1>

<p>Let’s define the Diffie-Hellman problem with color:</p>

<ul>
  <li>Give <code class="language-plaintext highlighter-rouge">g</code> to be the generator of the group, in this case we chose the color <code class="language-plaintext highlighter-rouge">g</code> in the RGBA in the color space.</li>
  <li>Let’s define the <code class="language-plaintext highlighter-rouge">^</code> to be the one way function, that is giving 2 color <code class="language-plaintext highlighter-rouge">x</code> and <code class="language-plaintext highlighter-rouge">y</code>, we can easily compute the mixed color <code class="language-plaintext highlighter-rouge">m=x^y</code>, but given the color <code class="language-plaintext highlighter-rouge">m</code>, it is “hard” to find the color which <code class="language-plaintext highlighter-rouge">m</code> is mixed from.</li>
  <li>The DHP in the color space will be: Give 2 color \(X\) and \(Y\), where as \(X=g^x\) and \(Y=g^y\), it is hard to find the color the color \(Z=(g^x)^y\)</li>
</ul>

<p>It sounds logical, right? Let’s take a closer look.</p>

<h1 id="color-mixing-algorithm">Color mixing algorithm</h1>

<p>For someone who is not familiar with graphic processing, color in image can be represent in several way, in this post, I use the RGBA which use Red-Green-Blue-Alpha element to represent color, and it is represented by a vector of 4 byte, however, in this blog post, I ignore the Alpha channel to reduce the complexity, se let’s assume all the alpha in this blog post is <code class="language-plaintext highlighter-rouge">1.0</code>. Here are some examples:</p>

<h2 style="background-color:rgba(255, 99, 71, 1.0 );">* rgb(255, 99, 71)</h2>
<h2 style="background-color:rgba(32, 99, 71, 1.0);">* rgb(32, 99, 71)</h2>
<h2 style="background-color:rgba(99, 99, 250, 1.0);">* rgb(99, 99, 250)</h2>

<p>Now we define the mix color operation, there are several one for this, but for the workable DH scheme, we will need the one that has the commutative and associative characteristic.</p>

<ul>
  <li>Option1 - Additive blending: C1(r1,g1,b1) ^ C2(r2,g2,b2) = Z(r1+r2, g1+g2,  b1+b2), it seems to match our imagination about the RGB color space, however, it has the problem about the saturation, our information will be lost. For instance, if one of the color in mixing is white (FFFFFF), the result is always wh/ite due to saturation.</li>
  <li>
    <p>Option2 - Average blending: On the surface, it is commutative, but it doesn’t provide associative. So I wanna make a modification for it.
\(F\) is the funcion which take the list of colors to produce the new color.</p>

    <p>\(F(color1)\) = \(color1\)</p>

    <p>\(F(color1, color2)\) = \((color1+color2)/2\)</p>

    <p>\(F(color1, color2, color3)\) = \((color1+color2+color3)/3\) = \(F(color1,color2)*2/3 + F(color3)*1/3\)</p>
  </li>
  <li>Option3 - Multiply blending: This is a common blend mode, the special effect of this mode is that the result is alway a color darker than 2 input colors. Here is the blend function for it
\(F(a,b) = a.b\) where as the result in RGB-888 notation is new \(Z\) color is  \(Rz = Ra.Rb/255; Gz = Ga.Gb/255; Bz=Ba.Bb/255\)</li>
</ul>

<p>Let’s see the illustration of the color blending in different modes.</p>

<table>
  <thead>
    <tr>
      <th>Mode</th>
      <th>Example</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Addition</td>
      <td><img src="https://link.storjshare.io/s/jwrwdsivuxf7px5e66djn4vcrxcq/blogimage/DHwithColor/AddictiveBLend.png?wrap=0" alt="" /></td>
    </tr>
    <tr>
      <td>Average</td>
      <td><img src="https://link.storjshare.io/s/jxinqesm5lkudhcmknoortkggbsa/blogimage/DHwithColor/AverageBlending.png?wrap=0" alt="" /></td>
    </tr>
    <tr>
      <td>Multiply</td>
      <td><img src="https://link.storjshare.io/s/jvjfpe6we2yr2zdntnlhywkhb4la/blogimage/DHwithColor/Multiply.png?wrap=0" alt="" /></td>
    </tr>
  </tbody>
</table>

<p>Based on the result of the blending, we can easily see addictive blending doesn’t fit with the realtiy of paint mixing, because the more we mix, the lighter it is, but it shall be darker in reality. However, we will accept it for the DH key exchange, just for reference.</p>

<h1 id="try-out-the-key-exchange-with-color-blending">Try out the key exchange with color blending</h1>

<p>Let’s make the key exchange between Alice and Bob, as the following table.</p>
<style type="text/css">
.tg  {border-collapse:collapse;border-spacing:0;}
.tg td{border-color:black;border-style:solid;border-width:1px;font-family:Arial, sans-serif;font-size:14px;
  overflow:hidden;padding:10px 5px;word-break:normal;}
.tg th{border-color:black;border-style:solid;border-width:1px;font-family:Arial, sans-serif;font-size:14px;
  font-weight:normal;overflow:hidden;padding:10px 5px;word-break:normal;}
.tg .tg-3v66{background-color:#0f0f0f;font-family:"Courier New", Courier, monospace !important;text-align:left;vertical-align:top}
.tg .tg-bt2x{background-color:#10f0c1;font-family:"Courier New", Courier, monospace !important;text-align:left;vertical-align:top}
.tg .tg-gg2y{background-color:#0fb002;font-family:"Courier New", Courier, monospace !important;text-align:left;vertical-align:top}
.tg .tg-u75l{background-color:#90ffff;font-family:"Courier New", Courier, monospace !important;text-align:left;vertical-align:top}
.tg .tg-nlez{background-color:#aae291;font-family:"Courier New", Courier, monospace !important;text-align:left;vertical-align:top}
.tg .tg-7eyh{background-color:#80f0d9;font-family:"Courier New", Courier, monospace !important;text-align:left;vertical-align:top}
.tg .tg-pl4m{background-color:#ffff82;font-family:"Courier New", Courier, monospace !important;text-align:left;vertical-align:top}
.tg .tg-lkdj{background-color:#0f0c00;font-family:"Courier New", Courier, monospace !important;text-align:left;vertical-align:top}
.tg .tg-w9rw{background-color:#876b09;font-family:"Courier New", Courier, monospace !important;text-align:left;vertical-align:top}
.tg .tg-8hba{background-color:#48b8a1;font-family:"Courier New", Courier, monospace !important;text-align:left;vertical-align:top}
.tg .tg-vs2s{background-color:#fffff2;font-family:"Courier New", Courier, monospace !important;text-align:left;vertical-align:top}
.tg .tg-a5yt{background-color:#609846;font-family:"Courier New", Courier, monospace !important;text-align:left;vertical-align:top}
.tg .tg-pgyx{background-color:#abe391;font-family:"Courier New", Courier, monospace !important;text-align:left;vertical-align:top}
.tg .tg-zop7{background-color:#0fb001;font-family:"Courier New", Courier, monospace !important;text-align:left;vertical-align:top}
.tg .tg-tyl5{background-color:#0fe2b6;font-family:"Courier New", Courier, monospace !important;text-align:left;vertical-align:top}
.tg .tg-3ote{background-color:#ffffd2;font-family:"Courier New", Courier, monospace !important;text-align:left;vertical-align:top}
.tg .tg-ad4u{background-color:#ffd611;font-family:"Courier New", Courier, monospace !important;text-align:left;vertical-align:top}
.tg .tg-fixl{background-color:#806401;font-family:"Courier New", Courier, monospace !important;text-align:left;vertical-align:top}
.tg .tg-0lax{text-align:left;vertical-align:top}
.tg .tg-ymsu{background-color:#f0f0f0;font-family:"Courier New", Courier, monospace !important;text-align:left;vertical-align:top}
.tg .tg-7fqw{background-color:#808080;font-family:"Courier New", Courier, monospace !important;text-align:left;vertical-align:top}
.tg .tg-bweo{background-color:#ffffff;font-family:"Courier New", Courier, monospace !important;text-align:left;vertical-align:top}
.tg .tg-03ip{background-color:#1fffd0;font-family:"Courier New", Courier, monospace !important;text-align:left;vertical-align:top}
.tg .tg-io95{background-color:#108068;font-family:"Courier New", Courier, monospace !important;text-align:left;vertical-align:top}
.tg .tg-r1pw{background-color:#087861;font-family:"Courier New", Courier, monospace !important;text-align:left;vertical-align:top}
.tg .tg-9kc8{background-color:#010e0b;font-family:"Courier New", Courier, monospace !important;text-align:left;vertical-align:top}
.tg .tg-t5fq{background-color:#ffc702;font-family:"Courier New", Courier, monospace !important;text-align:left;vertical-align:top}
.tg .tg-ay8z{background-color:#f8dc79;font-family:"Courier New", Courier, monospace !important;text-align:left;vertical-align:top}
.tg .tg-3dfx{background-color:#c0a441;font-family:"Courier New", Courier, monospace !important;text-align:left;vertical-align:top}
.tg .tg-wpuk{background-color:#f0bb02;font-family:"Courier New", Courier, monospace !important;text-align:left;vertical-align:top}
.tg .tg-juaj{background-color:#85bc6c;font-family:"Courier New", Courier, monospace !important;text-align:left;vertical-align:top}
.tg .tg-qag1{background-color:#5f9746;font-family:"Courier New", Courier, monospace !important;text-align:left;vertical-align:top}
.tg .tg-4d6x{background-color:#085e01;font-family:"Courier New", Courier, monospace !important;text-align:left;vertical-align:top}
.tg .tg-srmr{background-color:#010b00;font-family:"Courier New", Courier, monospace !important;text-align:left;vertical-align:top}
</style>

<table class="tg">
<thead>
  <tr>
    <th class="tg-0lax"> </th>
    <th class="tg-0lax" colspan="3">Addictive</th>
    <th class="tg-0lax" colspan="3">Average</th>
    <th class="tg-0lax" colspan="3">Multiply</th>
  </tr>
</thead>
<tbody>
  <tr>
    <td class="tg-0lax"> </td>
    <td class="tg-0lax">Near white</td>
    <td class="tg-0lax">Mid point</td>
    <td class="tg-0lax">Near black</td>
    <td class="tg-0lax">Near white</td>
    <td class="tg-0lax">Mid point</td>
    <td class="tg-0lax">Near black</td>
    <td class="tg-0lax">Near white</td>
    <td class="tg-0lax">Mid point</td>
    <td class="tg-0lax">Near black</td>
  </tr>
  <tr>
    <td class="tg-0lax">Common color G</td>
    <td class="tg-ymsu">F0F0F0</td>
    <td class="tg-7fqw">808080</td>
    <td class="tg-3v66">0F0F0F</td>
    <td class="tg-ymsu">F0F0F0</td>
    <td class="tg-7fqw">808080</td>
    <td class="tg-3v66">0F0F0F</td>
    <td class="tg-ymsu">F0F0F0</td>
    <td class="tg-7fqw">808080</td>
    <td class="tg-3v66">0F0F0F</td>
  </tr>
  <tr>
    <td class="tg-0lax">Alice's private color</td>
    <td class="tg-bt2x">10F0C1</td>
    <td class="tg-bt2x">10F0C1</td>
    <td class="tg-bt2x">10F0C1</td>
    <td class="tg-bt2x">10F0C1</td>
    <td class="tg-bt2x">10F0C1</td>
    <td class="tg-bt2x">10F0C1</td>
    <td class="tg-bt2x">10F0C1</td>
    <td class="tg-bt2x">10F0C1</td>
    <td class="tg-bt2x">10F0C1</td>
  </tr>
  <tr>
    <td class="tg-0lax">Alice's public color</td>
    <td class="tg-bweo">FFFFFF</td>
    <td class="tg-u75l">90FFFF</td>
    <td class="tg-03ip">1FFFD0</td>
    <td class="tg-7eyh">80F0D9</td>
    <td class="tg-8hba">48B8A1</td>
    <td class="tg-io95">108068</td>
    <td class="tg-tyl5">0FE2B6</td>
    <td class="tg-r1pw">087861</td>
    <td class="tg-9kc8">010E0B</td>
  </tr>
  <tr>
    <td class="tg-0lax">Bob's private color</td>
    <td class="tg-t5fq">FFC702</td>
    <td class="tg-t5fq">FFC702</td>
    <td class="tg-t5fq">FFC702</td>
    <td class="tg-t5fq">FFC702</td>
    <td class="tg-t5fq">FFC702</td>
    <td class="tg-t5fq">FFC702</td>
    <td class="tg-t5fq">FFC702</td>
    <td class="tg-t5fq">FFC702</td>
    <td class="tg-t5fq">FFC702</td>
  </tr>
  <tr>
    <td class="tg-0lax">Bob's public color</td>
    <td class="tg-vs2s">FFFFF2</td>
    <td class="tg-pl4m">FFFF82</td>
    <td class="tg-ad4u">FFD611</td>
    <td class="tg-ay8z">F8DC79</td>
    <td class="tg-3dfx">C0A441</td>
    <td class="tg-w9rw">876B09</td>
    <td class="tg-wpuk">F0BB02</td>
    <td class="tg-fixl">806401</td>
    <td class="tg-lkdj">0F0C00</td>
  </tr>
  <tr>
    <td class="tg-0lax">Alice's share secret</td>
    <td class="tg-bweo">FFFFFF</td>
    <td class="tg-bweo">FFFFFF</td>
    <td class="tg-3ote">FFFFD2</td>
    <td class="tg-pgyx">ABE391</td>
    <td class="tg-juaj">85BD6C</td>
    <td class="tg-qag1">5F9746</td>
    <td class="tg-gg2y">0FB002</td>
    <td class="tg-4d6x">085E01</td>
    <td class="tg-srmr">010B00</td>
  </tr>
  <tr>
    <td class="tg-0lax">Bob's share secret</td>
    <td class="tg-bweo">FFFFFF</td>
    <td class="tg-bweo">FFFFFF</td>
    <td class="tg-3ote">FFFFD2</td>
    <td class="tg-nlez">AAE291</td>
    <td class="tg-juaj">85BD6C</td>
    <td class="tg-a5yt">609846</td>
    <td class="tg-zop7">0FB001</td>
    <td class="tg-4d6x">085E01</td>
    <td class="tg-srmr">010B00</td>
  </tr>
</tbody>
</table>

<p>Then, looking at the table, we can see that all 3 options produce a viable way to do the DH key exchange using color, here are some of the observations:</p>
<ul>
  <li>We see that Alice and Bob can create the identical color, or nearly indentical color as as shared secret. There are the minor deviation in some cases (like the <code class="language-plaintext highlighter-rouge">Near white</code> case of the Avarage blending), this is simply the rounding error when the operation involve the number division.</li>
  <li>For the Addictive blending, the shared secret color can be obtained by both Alice and Bob, we can see that it indeed saturated to White color. Similarly, for the Multiply blending, the result can be quickly saturarted to Black color, though it is not as easy as white color, but from the human eyes resolution, the difference betwene black and near black color is negligible.</li>
  <li>If you are a good person in distinguishing color, you can see the final shared secret having some correlation with the public color.</li>
</ul>

<h1 id="trivial-security-evaluation">Trivial security evaluation</h1>

<p>We call it trivial because all above color blending mode are not truely one way function mathematically, because the private key are easily calculated from common g color and the public key, see the following:</p>

<ul>
  <li>Addictive blending: We can use the color subtraction.</li>
  <li>Average blending: We can use the linear interpolate or extrapolate to extract the private color.</li>
  <li>Muliply blending: We can use the public color divide to common g color and we will get the private color.</li>
</ul>

<p>With that said, we don’t really consider the mathematical characteristic of these operation, because it trivial to break the scheme. Thus we only evaluate the security properties of the scheme bases on the color visualization. Let’s see the following analysis:</p>

<ul>
  <li>
    <p>Addiction blending: we can easily see that this scheme work only if the g is near the dark color to avoid the saturation, at the same time, the private key should be chosen that it shall not cause the saturation. With that said, the result of the Color DH is always brighter color than the g and the public key itself, thus the attacker can just mix gx and gy, and brute force the color from (g^x)^y to g^x.</p>
  </li>
  <li>
    <p>Average blending: Well, I believe Average blending is the most accurate interm of color visualization, because it reflect the way we mix paint in real life. The share secret it this case is a bit harder to guess, because it can be brighter and darker than the public colors.</p>
  </li>
  <li>
    <p>Multiply blending: This scheme is the opposite of the Addiction blending, where it need the <code class="language-plaintext highlighter-rouge">g</code> color to be near the while color, and the result of the blending is always the darker color. Though this scheme does not cause much of the saturation problem (unless one of the serecet color is completely black - represent by <code class="language-plaintext highlighter-rouge">0</code> value), it does not represent the real color blending in reality. For instance, if we mix 2 color of the same color, the result shall be the same color in real life, but with this multiply color bleanding, we get the darker color.</p>
  </li>
</ul>

<h1 id="afterthought">Afterthought</h1>
<p>I have realized that using the RGB color model is not appropriate with the paint mixing analogy key exchange, since the RGB is the Addictive color model, it represent light emission. While in case of the paint mixing, paint has color X because it absort all the light of the other color than X (or it reflect and scatter the X color), thus the CMYK color model should be more appropriate. However, the blending operation would be the same, as my time is limited, I let this post as it is and I will update this post in the future to demonstrate color blending in CMYK color space.</p>

<p>I have also read some discussion about color blending modeling in math, it seems that with the current common color model, it is difficult to make the mathermatical representation of the color blending to be exact as we see in reality, because color mixing is not only about the light mixing but also the chemical reaction and biological phenomenon of the human eye. For instance, all 3 mode of color blending in our example are associative, but in reality, when we mix color (A+B) then mix with C, that result will be different from when we mix the (B+C) then mix with A, the order of paint mixing does matter in some case. During the time I write this blog post I have found these interesting post:</p>
<ul>
  <li><a href="https://blog.ploeh.dk/2018/01/02/colour-mixing-magma/">Colour-mixing magma by Mark Seemann</a></li>
  <li><a href="https://en.wikipedia.org/wiki/Color_theory">Color theory (I haven’t known it exist) on Wikipeia</a></li>
</ul>

<p><strong>Last but not least, this blog post is purely for entertainment + self education purpose. It may contains some oversimplified technical detail, by no mean, I am trying to propose color blending operation as a DH key exchange in the serious application.</strong></p>]]></content><author><name>Truong</name></author><category term="Shower thought" /><category term="Learning" /><summary type="html"><![CDATA[The first time I learn about key exchange protocol, I came across an analogy of the protocol using color mixing (Wikipedia image). This analogy is easy to understand, but does it actually work, ignoring the fact that it may be insecure. Let’s see now.]]></summary></entry><entry><title type="html">Learning Haskell Diary (Part #6): Category Theory, Maybe, Just, Nothing, and Monad</title><link href="/engineering/Haskell-learning-diary-d6/" rel="alternate" type="text/html" title="Learning Haskell Diary (Part #6): Category Theory, Maybe, Just, Nothing, and Monad" /><published>2023-07-06T00:00:00+00:00</published><updated>2023-07-06T00:00:00+00:00</updated><id>/engineering/Haskell-learning-diary-d6</id><content type="html" xml:base="/engineering/Haskell-learning-diary-d6/"><![CDATA[<h1 id="recap-after-half-a-year">Recap After Half a Year</h1>

<p>Been learning Haskell intensively from last year, starting with some fundamental knowledge about category theory. I have been exploring the concepts of functors and monads, particularly focusing on understanding category theory. To aid in my learning journey, I came across a valuable resource: Dr. Bartosz Milewski’s YouTube channel. His series of lecture videos on Category Theory for programmers have been immensely helpful. They have not only piqued my interest but also provided me with new perspectives on the programming work I have been doing for years, making me contemplate the quality of my code and the potential bugs that may arise due to the imperative nature of certain languages.</p>

<h1 id="some-ideas-from-category-theory">Some Ideas from Category Theory</h1>

<h2 id="another-way-of-abstraction">Another Way of Abstraction</h2>

<p>Category theory introduces a novel approach to abstraction. It represents things as dots (objects) and arrows (morphisms). A category should exhibit the following characteristics:</p>

<ul>
  <li>Identity operation: This morphism maps an object to itself. <code class="language-plaintext highlighter-rouge">id x = x</code></li>
  <li>Composition: When applying morphism <code class="language-plaintext highlighter-rouge">f</code> from object <code class="language-plaintext highlighter-rouge">a</code> to object <code class="language-plaintext highlighter-rouge">b</code>, and then morphism <code class="language-plaintext highlighter-rouge">g</code> from object <code class="language-plaintext highlighter-rouge">b</code> to object <code class="language-plaintext highlighter-rouge">c</code>, the resulting morphism <code class="language-plaintext highlighter-rouge">g . f</code> (called g after f) should satisfy <code class="language-plaintext highlighter-rouge">g . f = a -&gt; c</code>.</li>
</ul>

<h1 id="examples-of-using-category-theory-to-abstract-common-mathematical-characteristics">Example(s) of Using Category Theory to Abstract Common Mathematical Characteristics</h1>

<p>These are my own interpretations, which may not perfectly align with the theory, but they demonstrate how I perceive the topic.</p>

<h3 id="the-adder-and-number-zero-andor-the-multiplier-and-number-one">The Adder and Number Zero, and/or the Multiplier and Number One</h3>

<p>Although addition and multiplication are distinct operations we learn as children, mathematical abstraction reveals similarities between the two. I use the symbol <code class="language-plaintext highlighter-rouge">^</code> to represent the operator:</p>

<ul>
  <li>Composition: <code class="language-plaintext highlighter-rouge">(a^b)^c = a^(b^c)</code></li>
  <li>Commutative property: <code class="language-plaintext highlighter-rouge">a^b = b^a</code></li>
  <li>Identity element: <code class="language-plaintext highlighter-rouge">I</code> is the identity element, ensuring that for every number, the operation <code class="language-plaintext highlighter-rouge">x ^ I = I ^ x = x</code>.</li>
  <li>For every operation <code class="language-plaintext highlighter-rouge">f</code> and <code class="language-plaintext highlighter-rouge">g</code> in set M, the composition <code class="language-plaintext highlighter-rouge">f x g</code> is also in set M.</li>
</ul>

<p>We observe that these characteristics align with the number zero for addition and the number one for multiplication. Category theory addresses such special characteristics in a more abstract manner, referring to them as monoids. The diagram below (image from Wikipedia) depicts a monoid:
<img src="https://upload.wikimedia.org/wikipedia/commons/thumb/a/a4/Monoid_unit_svg.svg/726px-Monoid_unit_svg.svg.png" alt="Monoid diagram" /></p>

<p>Initially, this diagram might appear overwhelming, but after watching <a href="https://www.youtube.com/watch?v=GmgoPd7VQ9Q">Dr. Bartosz’s lecture on monoids</a>, I gained a better understanding. In general, a monoid is defined within a category with the following morphisms:</p>
<ul>
  <li>\(\mu\): M ⊗ M -&gt; M. This represents multiplication or the binary operator, mapping a pair of objects of the same type to an object of the same type.</li>
  <li>\(\eta\): I -&gt; M. Here, I denotes the unit. Although I haven’t fully grasped this concept yet, I accept it for the time being and continue my search for answers.</li>
</ul>

<p>For this particular category, the following characteristics hold:</p>
<ul>
  <li>Multiplication: Morphism of a pair of objects to an object. For example, the multiplication of two real numbers yields a real number.</li>
  <li>Associativity: Suppose we have \(\mu\) (\(\mu\)(x,y),z) = \(\mu\) (x,\(\mu\)(y,z)). This equation represents the associativity of real number multiplication.</li>
  <li>Identity: We have \(\mu\) (\(\eta\) (I), x) = \(\mu\) (x,\(\eta\) (I)) = x, denoted as left identity and right identity (\(\lambda\) and \(\rho\)) in the diagram. For instance, in multiplication, the number <strong>1</strong> serves as the identity element.</li>
</ul>

<h2 id="and-then-the-monad">And Then the Monad</h2>

<p>Monad? Another new term. I have been struggling to grasp the most fascinating concept of Haskell and Category theory. In fact, I even paused my Haskell coding practice to read and watch numerous articles and videos to gain a better understanding. However, I needed to set aside the concept of category theory temporarily to comprehend monads from an imperative perspective.</p>

<p>Let’s consider Haskell, a pure functional language where functions are pure and do not modify state variables or cause side effects such as writing to files, sending data over the internet, or altering registers (I happen to be an embedded software engineer). At this point, a question arises: Why are pure functions essential in functional programming? In Haskell, we do not have expressions like <code class="language-plaintext highlighter-rouge">count = count+1</code> because they violate the principles of the mathematical universe. Impure functions lead to the collapse of lazy evaluation, thus rendering function composition and eta reduction are inefficient.
<img src="https://link.storjshare.io/s/jug25lvteqn3jo4f6ns7kbyocx7a/imagehosting/photo_2023-07-08_14-48-48.jpg?wrap=0" alt="Lazy evaluation collapse" /></p>

<p>Allow me to provide an example illustrating the use of monads. I will not delve into the definition of a monad for now. This explanation draws inspiration from <a href="https://web.archive.org/web/20120114225257/http://ertes.de/articles/monads.html">Ertugrul Söylemez’s blog post</a>.</p>

<p>Let’s assume we implement an integer square root function that takes an integer and returns its square root. We can represent this function as shown in the following figure:
<img src="https://link.storjshare.io/s/jvlinhdvoxzdbzeatmgph6gsidrq/blogimage/monad/i_sqrt.png?wrap=0" alt="Integer square root" /></p>

<p>However, as you know, this function has its limitations. It can only return numeric values, and for certain inputs like 17, an integer root does not exist. How can we address this problem? In C, we solve it by providing a function that returns the validity of the result via another <em>pass by reference</em> variable, as shown below:
<img src="https://link.storjshare.io/s/jxikev6oeihdtbjhlokyensc4erq/blogimage/monad/safesqrt.png?wrap=0" alt="Safe square root" /></p>

<p>The problem with this approach is evident: the function is impure due to the modification of the global variable <code class="language-plaintext highlighter-rouge">pRet</code>. So, what’s the point? Why do we emphasize the purity of Haskell if it does not simplify our lives? Suppose we want to compute the positive fourth root, which can be expressed as:
\(\sqrt[4]{x} = \sqrt{\sqrt{x}}\)</p>

<p>We can implement the fourth root of an integer using the function depicted in the following block diagram:
<img src="https://link.storjshare.io/s/jwap57d37uzedipvsqepfe7o2yka/blogimage/monad/pure_fourthroot.png?wrap=0" alt="Pure fourth root" /></p>

<p>As previously discussed, the square root function presents several problems, which are carried forward when computing the fourth root. So, how can we correctly compose the <code class="language-plaintext highlighter-rouge">sqrt</code> function? Haskell, and mathematics in general, provide a solution.</p>

<p>Suppose we can define a type that represents whether the function’s return value is an integer or <code class="language-plaintext highlighter-rouge">Nothing</code>. In Haskell, we call this type <code class="language-plaintext highlighter-rouge">Maybe Int</code>. The function signature for this approach is depicted in the following diagram:
<img src="https://link.storjshare.io/s/jxlruhm23j34rzyludmzjgde7mza/blogimage/monad/maybe_sqrt.png?wrap=0" alt="Maybe square root" /></p>

<p>Looking at the diagram, we can simulate a similar approach in C by returning a structure that represents the <code class="language-plaintext highlighter-rouge">Maybe Integer</code> type. However, what is the advantage? One crucial aspect is that we still pass an integer as the input value, as the square root function operates on integers. Another significant advantage is that by avoiding the use of global variables, the function remains pure and preserves laziness. Moreover, we can use a special composition technique known as bind (<code class="language-plaintext highlighter-rouge">&gt;&gt;=</code>) operation to compose functions. Let’s examine how we compose <code class="language-plaintext highlighter-rouge">i_sqrt</code> into <code class="language-plaintext highlighter-rouge">fourth_sqrt</code> in the following figure:
<img src="https://link.storjshare.io/s/juk56ofv26cewcdo7bagdbriu5qq/blogimage/monad/monad_fourthroot.png?wrap=0" alt="Monad fourth root" /></p>

<p>Analyzing the diagram, we observe that the fourth root function is implemented by composing two <code class="language-plaintext highlighter-rouge">i_sqrt</code> functions. The composition is special because it not only passes the output of the first function as the input of the second function (like the dot <code class="language-plaintext highlighter-rouge">(.)</code> operation in Haskell), but it also handles cases where the first <code class="language-plaintext highlighter-rouge">i_sqrt</code> function yields <code class="language-plaintext highlighter-rouge">Nothing</code>. In such cases, <code class="language-plaintext highlighter-rouge">Nothing</code> is directly forwarded to the output without passing through the second <code class="language-plaintext highlighter-rouge">i_sqrt</code> box. This behavior aligns with the definition of the bind (<code class="language-plaintext highlighter-rouge">&gt;&gt;=</code>) function in the Maybe Monad. The Haskell definition is as follows:</p>

<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="o">&gt;&gt;=</span><span class="p">)</span> <span class="o">::</span> <span class="kt">Maybe</span> <span class="n">a</span> <span class="o">-&gt;</span> <span class="p">(</span><span class="n">a</span> <span class="o">-&gt;</span> <span class="kt">Maybe</span> <span class="n">b</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kt">Maybe</span> <span class="n">b</span>
<span class="p">(</span><span class="o">&gt;&gt;=</span><span class="p">)</span> <span class="n">m</span> <span class="n">g</span> <span class="o">=</span> <span class="kr">case</span> <span class="n">m</span> <span class="kr">of</span>
                   <span class="kt">Nothing</span> <span class="o">-&gt;</span> <span class="kt">Nothing</span>
                   <span class="kt">Just</span> <span class="n">x</span>  <span class="o">-&gt;</span> <span class="n">g</span>
</code></pre></div></div>
<p>As we can see, the Monad is precisely defined, serving its purpose. This example highlights a few key benefits of using monads:</p>

<ul>
  <li>It facilitates function composition in a special and potentially clever way.</li>
  <li>In the i_fourth_sqrt function mentioned above, the intermediate calculation after the first i_sqrt is encapsulated within the bind function. We no longer require global variables to store the state of the first i_sqrt result or any temporary variables. Additionally, we can skip the second i_sqrt block if the immediate result is Nothing, thanks to lazy evaluation.</li>
  <li>Monads aid in abstracting calculations, hiding intricate details and allowing us to focus on high-level computations.
Last- ly, while error handling is not the primary purpose of monads, they provide a useful tool for handling error cases.</li>
</ul>

<p>To conclude this blog post, let’s revisit the original definition of a Monad found in some textbooks:</p>
<blockquote>
  <p>A Monad is a monoid in the category of endofunctors.</p>
</blockquote>

<p>When we examine what defines a monoid, we find:</p>

<ul>
  <li>The binary operator (»=): Composing two functors. It’s worth noting that functions can be seen as instances of functors. In the square root example mentioned earlier, the endofunctor maps from the category of integers to the category of integers (the mapping from the category to itself).</li>
  <li>The unit element, which in Haskell is the return function. In the i_sqrt function, the return function of the Maybe monad is Just.</li>
  <li>Associativity of the bind operator.</li>
</ul>

<p>I hope this example sheds some light on the usefulness of monads. While I’ve only listed a few benefits here, the true power of monads extends beyond error handling. It allows for clever function composition and abstracts computations, enabling us to focus on higher-level concepts.</p>

<p>That concludes this part of my blog post, as I fear my explanations might become convoluted if I continue.</p>]]></content><author><name>Truong</name></author><category term="Engineering" /><category term="Learning" /><category term="Haskell" /><category term="Category theory" /><category term="Functional programming" /><summary type="html"><![CDATA[Recap After Half a Year]]></summary></entry><entry><title type="html">…What did AUTOSAR solve?</title><link href="/thinking/Golden-comment-about-autosar/" rel="alternate" type="text/html" title="…What did AUTOSAR solve?" /><published>2023-06-19T00:00:00+00:00</published><updated>2023-06-19T00:00:00+00:00</updated><id>/thinking/Golden-comment-about-autosar</id><content type="html" xml:base="/thinking/Golden-comment-about-autosar/"><![CDATA[<p>As a tradition, when some guys on the internet asking about career path in automotive embedded software. This reddit comment pop-up in my mind. I am worrying that some day, this golden comment being destroyed, thus I backup here.</p>

<p><a href="https://www.reddit.com/r/embedded/comments/leq366/comment/gmiq6d0/?utm_source=share&amp;utm_medium=web3x&amp;utm_name=web3xcss&amp;utm_term=1&amp;utm_content=share_button">The original comment</a></p>

<blockquote>
  <blockquote>
    <p>What did AUTOSAR solve?</p>
  </blockquote>

  <p>It’s a job creator for application engineers.</p>

  <blockquote>
    <p>Did software become less complex and easier to develop/configure?</p>
  </blockquote>

  <p>Jesus fucking christ fuck no.</p>

  <blockquote>
    <p>Did the software become smaller or faster with AUTOSAR?</p>
  </blockquote>

  <p>See above.</p>

  <p>Forgive my vulgarity.</p>

  <p>I spent 2+ years trying to unfuck an existing AUTOSAR project at a company that builds vehicle telematic ECUs. I can safely say that the AUTOSAR standard and all available implementations (Vector, Mentor Graphics, and Electrobit) is an upside-down on fire dumpster full of dog shit.</p>

  <p>I’m not even gonna go into how much trouble it is to get the attention of an AUTOSAR distributor. If you’re a student or small business and you just want to see the specification then you can go grab it from autosar.org. It’s just a bunch of PDFs and they’re all free. But the implementation is where you’ll spend money, and if you aren’t Ford / GM / some automotive startup with a shit ton of money, nobody will want to talk to you because AUTOSAR is \(\)\(\)$$.</p>

  <p>Let’s assume you get past all that. After you spend months negotiating contracts with Mentor Fuckups or Eletroshit or whatever AUTOSAR package you decided was the least bad, you’ll spend a few more months sitting in online seminars while some talking head explains why it takes 6 hours to configure a million goddamn things so their garbage tool can shit out an entire Italian resaurant’s worth of spaghetti code just to blink an LED at 1Hz. Except it’s not 1Hz, it’s 10Hz, or 0.1Hz, or some other bullshit that you didn’t want, because you muttered the wrong incantation to the configuration utility somewhere around step 2 out of 800, so guess what, you get to back and do the entire fucking thing again.</p>

  <p>Get the flying fuck out of here if you want to try doing something more complicated than that. You want to send a CAN frame? Get completely fucked. You have to buy a separate tool beyond what you already spent $800k on just to generate the stupid little ARXML “network definitions” files that are compatible with your AUTOSAR configurator, learn how to use that, then fight problems between export / import because of course both tools were written by different teams and aren’t 100% compatible (WHY THE FUCK WOULD ANYTHING EVER JUST FUCKING WORK?), then get your application developers to understand how to interface their C code to the new “network interface layer”, and etc etc etc.</p>

  <p>Now let’s assume you’re track-side and you want to add a new CAN signal just to get some info out of your ECU. With vanilla C it’s a matter of hacking something in quickly OR running some custom interface generation script that takes a few seconds, like the howerj/dbcc scripts. AUTOSAR? Hours. Literally even days if something goes wrong and your entire project blows up. Our firmware test turn-around window was weeks just because it took so long to get the network definition generator to spit out something useful without breaking a million other things, all the while the AUTOSAR vendor gave us excuse after excuse, patch after patch, never really fixing the problem.</p>

  <p>The final straw came when we realized we couldn’t hire anyone who would want to mess with this shit. Imagine working in the industry for 10 years, and then you take a job where someone says “Hey thanks for spending all that time learning all that cool stuff that we can’t use, here’s the MSPaint equivalent of embedded software development platforms, we need Mona Lisa by lunch.” Our choice was either over-pay seniors to deal with this giant pile of 5th stage super-cancer, or hire kids fresh out of college and hope they wouldn’t wise up to the fact that any skillset developed while working with AUTOSHIT was absolutely useless and bail.</p>

  <p>After 2 years with 20+ engineers working like this we gave up. Everyone else went on vacation while 3 guys spent a few days getting ADC ports, CAN, LIN, SPI, and a few other things up an running on a development kit. We had a working ECU running on a vehicle less than 2 weeks later. And that was from starting with a clean install of a compiler + IDE and a blank main.c. Our code safety team ran it through the ISO26262 verification process and everyone’s stress level was suddenly much lower because they could actually DO THE JOB THEY WERE HIRED TO DO instead of fighting the trash-tier AUTOSAR tool all day.</p>

  <p>I would rather shove a shotgun in my ass and blow my god damn balls off than ever lay my eyes on AUTOSHIT ever again. Complete fucking waste of time. If ever you see AUTOSAR on a job description then fucking RUN.</p>

</blockquote>]]></content><author><name>Truong</name></author><category term="Thinking" /><category term="Funny" /><summary type="html"><![CDATA[As a tradition, when some guys on the internet asking about career path in automotive embedded software. This reddit comment pop-up in my mind. I am worrying that some day, this golden comment being destroyed, thus I backup here.]]></summary></entry><entry><title type="html">After a week chat chitting with chatGPT</title><link href="/engineering/Review-chatGPT/" rel="alternate" type="text/html" title="After a week chat chitting with chatGPT" /><published>2022-12-24T00:00:00+00:00</published><updated>2022-12-24T00:00:00+00:00</updated><id>/engineering/Review-chatGPT</id><content type="html" xml:base="/engineering/Review-chatGPT/"><![CDATA[<p>Ok, ChatGPT is flooding the media, people are crazy about it. As an guy who codes for food, why not try it then.</p>

<h1 id="how-to-start">How to start</h1>

<p>Just google `open AI chatGPT” and you will be guide to the chatGPT link, unfortunately, at the moment, it is currently geographically blocking Vietnam user, there are several workaround you can find out there.</p>

<p>Let’s get started</p>

<h1 id="the-feel">The feel</h1>

<p>Obviously, as an machine under the hood, chating with it is not something like the human, however, for the purpose I am wanna try, it is interesting than using google search, but it is lke using the google assistance, except that this bot is not internet connected, but use their historical trained data. I guess openAI have provided it massive knowledge.</p>

<p>One think I was always wanna do but hate to learn is the GUI, like <a href="https://www.ted.com/talks/linus_torvalds_the_mind_behind_linux">Linus Tovard spoke in TED session with Chris Anderson</a>. Then, I have asked the bot to generate the code of simple GUI program (adder of 2 input numbers). As first, to be frank, I am scared of what it can do, it provide the initial version, then I complain, and it provides the revised version, and it did excellence for several round. The fololwing is the simplified <em>conversation</em> between myself and the bot.</p>

<h1 id="well-it-is-really-terifying-but-in-the-end-it-is-just-the-massive-if-else-isnt-it">Well it is really terifying, but in the end, it is just the massive if-else, isn’t it</h1>

<p>I am a fool, I am always think of the neural-network works like the massive if-else mesh. After couple of hours playing with in, I am convinced about the capabliity of the context in generated</p>

<ul>
  <li>
    <p>My goal is to make an salary calculator in python with GUI:</p>

    <ul>
      <li>
        <p>I wanna learn a bit of the GUI in python so I asked the bot to generate the simple GUI app, with some input textbox and one calculate button. I copied the python code it gen and run it run pretty well.</p>
      </li>
      <li>
        <p>I see the font is quite small, so I asked chatbot to increase the font size. Well It remembers the previous code and it generates the code to change the font size. Moreover, it also explains to me the code like a teacher, cool huh? I like it.</p>
      </li>
      <li>
        <p>Tweaking my questions some more rounds, and it performs like an expert in python. The content it generates having the consideration of the whole discussion, not just the dry ass Q&amp;A.</p>
      </li>
      <li>
        <p>However, when it comes to some bugy code it generates, I copied the error to the chat box to challenge our bot. It started to behaves like a junior, haha. I have tried to simplify my question, it seems to help a bit, but it cannot hide the fact that the code it generate is not from itself but the mix of some unknow expert in stackoverflow (haha).</p>
      </li>
    </ul>
  </li>
  <li>
    <p>Actually, my plan of learning haskell is abit behind the schedule, because I am so stupid to understand the monoid, monad, <code class="language-plaintext highlighter-rouge">May be</code>,… So I would like to check if it can be my mentor during the learning. So was asking the following question.</p>

    <ul>
      <li>In the ELI5, what is the functor in category theory. The following image is the outcome. Impressive huh?
<img src="https://link.storjshare.io/s/jub7qbaczwd2auzjhhfafxwbvx3q/imagehosting/GPTLearn1.png?wrap=0" alt="" />
<img src="https://link.storjshare.io/s/jv4usgfd7ohb6hvp2mujuolen3nq/imagehosting/GPTlearn2.png?wrap=0" alt="" /></li>
    </ul>
  </li>
</ul>

<h1 id="what-we-should-prepare-as-an-engineer">What we should prepare as an engineer?</h1>

<p>For me, with above 2 simples example, the chat bot like GPT really awesome to the point that would put some pressure on us, chat GPT seems to to compete with us, the engineer in these tedious job (like implement some low complex requirements). That may not immediately affect our job now, but the junior engineer would be in the difficult market now. Frankly, if I was able to use my 2 hours of engineering to tell the GPT to make some simple app, which may take a whole week or more of a junior, I would prefer worknig with chat GPT (I hate working with human haha).</p>

<h1 id="personal-verdict">Personal verdict?</h1>

<p>Think of how magically our brains are, I don’t think we could build the “skynet” that is superior the humankind intelligence in total (and the skynet without weapon connected is harmless, isn’t it?), I think the main reason the chatGPT is disconnected from the internet is to ensure that it cannot learn the negative stuff from the humankind, thus their purpose is achieve with just a little side effect. However, as an egineer. What I can see that it can generate the simple code that it would take me a day or so to do, in just a few minute. Thas is really impressive. Then it is that, the chatGPT cannot handle the much of the complexity like a middle engineer, but for simple task like writing some small module we normally see the entry level engineer did, I am afraid that these job will bee soon replace if the cost/performance of chatGPT is considered. The it is not the end of the our career for sure, for instance, before the calculator is invented, we still doing the math on paper. And when the calculator and computational science is rolling out, it is not mean that we can fire the mathenmatician or we can skip the Algebra 101 class in the college. ChatGPT or equivalent tools will be the powerfull tool to do the tedious job of the programming, like the calculation remove our stress of incorrect calculation, or like the computer spreadsheet (and database recently) replace the paper-and-pen book keeping.</p>]]></content><author><name>Truong</name></author><category term="Engineering" /><category term="Learning" /><category term="Review" /><category term="AI" /><summary type="html"><![CDATA[Ok, ChatGPT is flooding the media, people are crazy about it. As an guy who codes for food, why not try it then.]]></summary></entry></feed>