Thursday, July 02, 2026

Trust, But Verify: Reverse-Engineering a Wallet's Key Derivation

"Non-custodial" is a claim, not a fact. Any wallet can say your keys never leave your device — the only way to actually know is to open the source, find the code that turns your seed phrase into a private key, and check it yourself. That's true reverse engineering, and it's the same instinct behind WalletScrutiny's reproducible-build work: don't trust the label on the box, verify what's inside.

This post walks through doing exactly that for ADAMANT Messenger, an open-source decentralized messenger with a built-in multi-coin wallet (ADM, BTC, ETH, DOGE, DASH, USDT, USDC, ERC-20 tokens). The trigger was simple: I exported my passphrase from ADAMANT, tried to import it into Electrum as a BTC seed, and got a completely different address than the one ADAMANT shows me. Same passphrase, two different wallets, two different answers for "where is my money." That mismatch is either a red flag or a clue — this post is about figuring out which.




Part 1 — The methodology: how do you even start?

You don't need to be a cryptographer or a full-time programmer to do this. You need a computer, a terminal (the black-box text window your OS ships with — Terminal on macOS, or a shell like bash on Linux), and two free tools: git (downloads a copy of a project's source code) and grep (searches text). Both come pre-installed on Linux and macOS; on Windows, install Git for Windows, which bundles a terminal (Git Bash) with both tools already in it.


Step 1 — Get the actual source code onto your computer

"Open source" means the company publishes their code on a site like GitHub — but that code isn't on your machine yet, and you can't grep a website. The first real step is always to download ("clone") a copy of the repository. ADAMANT publishes theirs at github.com/Adamant-im/adamant-im. To clone it, open your terminal and run:

git clone https://github.com/Adamant-im/adamant-im.git

This creates a new folder called adamant-im in whatever directory you were in, containing a full copy of every source file in the project. Move into it:

cd adamant-im

Everything from here on happens inside that folder.

Step 2 — Frame the question before you start searching

Before touching ADAMANT's code, it helps to separate the mismatch (ADAMANT's address vs. Electrum's address, for the same passphrase) into two possibilities:

The two apps are using completely different derivation algorithms — different math entirely, or
They're using the same algorithm but different parameters (a different "derivation path," a different address format, different network settings).

That framing matters because it tells you what you're hunting for isn't "bitcoin code" in general — it's specifically the one function that takes a string (your passphrase) and turns it into a private key (a secret number that controls funds). That's a much smaller target than "the whole wallet app," which for ADAMANT is hundreds of files.

Step 3 — Where to look in a JS/TS wallet repo

ADAMANT is written in JavaScript/TypeScript (you can tell from the .js/.ts/.vue files when you look inside the folder — ls or your file manager will show you). Two complementary ways to narrow hundreds of files down to the handful that matter:

1. Look at the folder structure first. Multi-coin wallet apps almost always organize code per-coin or in a shared "coin logic" module. Run ls src/lib/ inside the cloned repo and look for folder names like wallets/, coins/, crypto/, or — in ADAMANT's case — bitcoin/. That's usually a strong hint before you've read a single line of code.

2. Search ("grep") for the vocabulary of key derivation. grep searches every file for a piece of text you give it. The trick is knowing which words to search for — key-derivation code almost always uses a handful of recognizable terms regardless of which wallet app you're looking at:

bip39, bip32 — names of the standards most wallets use to turn a 12/24-word phrase into keys
hdkey, derivePath — "HD" (Hierarchical Deterministic) wallet code, the mechanism behind those standards
mnemonicToSeed, fromPrivateKey — common function names in crypto libraries
bitcoinjs — the most popular JavaScript Bitcoin library, and a good sign you've found the right area

Run this from inside the adamant-im folder:

grep -rniE "bip39|bip32|hdkey|derivePath|mnemonicToSeed|fromPrivateKey|bitcoinjs" \
--include="*.js" --include="*.ts" -l

Breaking that command down: grep is the search tool; -r means "search recursively" (every file in every subfolder, not just the current one); -n shows line numbers; -i ignores uppercase/lowercase differences; -E allows the | ("or") syntax between search terms; --include="*.js" restricts the search to JavaScript/TypeScript files so you're not wading through images or config files; -l prints just the filenames that matched, not every matching line (useful for a first pass).

Run that before reading anything else. It narrows an entire repository (hundreds of files) down to 3-5 files worth opening by hand.

Step 4 — Read the smallest function that touches "passphrase" and "key"

Running that grep against the ADAMANT repo points straight at one file: src/lib/bitcoin/btc-base-api.js. Open it in any text editor (even a basic one) and look for a function — a named, reusable block of code — that takes the passphrase as input. Here it is, in full, with nothing trimmed out:

export function getAccount(crypto, passphrase) {
const network = networks[crypto]
const pwHash = bitcoin.crypto.sha256(Buffer.from(passphrase))
const keyPair = ECPairAPI.fromPrivateKey(pwHash, { network })

return {
network,
keyPair,
address: bitcoin.payments.p2pkh({ pubkey: keyPair.publicKey, network }).address
}
}

A quick vocabulary check, since none of this is obvious on a first read:

sha256 — a hashing function. Feed it any input (here, your passphrase as plain text) and it always produces the exact same 32-byte output for that input, every time, on any computer. That determinism is exactly what makes a wallet "non-custodial": no server is involved, no randomness, just math you can rerun yourself.

secp256k1 — the specific elliptic curve (a type of math used for cryptographic keys) that Bitcoin, and this wallet, build private/public key pairs on. You don't need to understand the curve math — just know that a "private key" for secp256k1 is simply a 32-byte number, and the SHA256 output above is exactly 32 bytes, which is why it can be used directly as one.

P2PKH ("Pay to Public Key Hash") — the oldest, simplest Bitcoin address format, the kind that starts with 1. There are newer formats, but P2PKH is what this code produces.
So the whole derivation, stripped of jargon, is:

private_key = SHA256(the passphrase, typed exactly as shown, as raw text)
address     = a Bitcoin "1..." address computed from that private key

No BIP32 master key, no derivation path like m/44'/0'/0'/0/0, no PBKDF2 (a slow-hashing step BIP39 wallets use). Just one SHA256 hash of the literal passphrase text, used directly as a private key.

A necessary terminology correction: "passphrase" vs. "seed phrase" vs. "BIP39 passphrase"
Before going further, three words that sound similar but mean different things need untangling — because ADAMANT's own naming makes this genuinely confusing, even for people who already know standard Bitcoin wallet terms.

Seed phrase / mnemonic — the 12 (or 15/18/21/24) words most wallets show you on first setup ("write these down"). These are generated by the app itself, drawn from a fixed, public list of exactly 2048 words defined by the BIP39 standard. You don't get to pick them; the app picks them for you from device randomness.

BIP39 passphrase (sometimes called the "25th word") — a completely separate, optional extra secret that some wallets let you add on top of the 12-word mnemonic. Unlike the mnemonic, this one genuinely is user-typed, arbitrary text — any word or sentence you want, not restricted to the 2048-word list. If you set one, it gets mixed into the seed-derivation math alongside the mnemonic; the same 12 words plus a different (or missing) passphrase produce a completely different wallet. It exists mainly for plausible deniability (a "decoy" wallet vs. a "real" one, both reachable from the same 12 words).

What ADAMANT calls "passphrase" — despite the name, this is actually the first thing on this list, not the second. Checking src/components/PassphraseGenerator.vue confirms it: passphrase.value = bip39.generateMnemonic() — ADAMANT generates it the exact same way a standard BIP39 wallet generates its seed phrase (real entropy, real 2048-word list, real checksum, machine-generated, not user-typed). ADAMANT's product team just chose to call their seed phrase a "passphrase" in the UI and the code, which collides with the actual BIP39 meaning of that word above. When this post says "ADAMANT passphrase" from here on, it means ADAMANT's seed phrase — the 12-word mnemonic — not an optional 25th-word extension.

It gets more interesting: not every coin gets the same treatment


Given that ADAMANT's "passphrase" is a real, valid BIP39 mnemonic, a natural next question is whether it's used the standard BIP39 way. The answer is: it depends on which coin, and this is the most surprising thing this investigation turned up.

Grepping src/lib/ for mnemonicToSeedSync (the actual BIP39 function that turns a mnemonic into a 64-byte seed) shows three different fates for the same 12 words:

CoinUses BIP39's mnemonicToSeedSync?What happens nextReproducible in a standard wallet?
BTC / DOGE / DASHNo — skipped entirelySHA256(raw mnemonic text) directlyNever. No standard wallet can replicate this; the BIP39 seed step is bypassed altogether.
ADM (native coin)Yes (src/lib/adamant.js)Seed is then hashed again with SHA256 and fed into an Ed25519 keypair function (sodium.crypto_sign_seed_keypair) — a Lisk-style step, not part of BIP39/32/44Only by a wallet that reimplements this exact extra step. (ADAMANT is a fork of Lisk, and this is Lisk's own historical scheme.)
ETH (src/lib/eth-utils.js)YesStandard BIP32 HD derivation — but at a nonstandard path, m/44'/60'/3'/1/0, instead of the usual default m/44'/60'/0'/0/0Only if you manually type that exact custom path. Any wallet that lets you override the derivation path (MetaMask's advanced settings, Ledger Live, many others) can get there — just not with default settings.

So "does ADAMANT use BIP39" doesn't have one answer — it's "yes for the seed-generation step, on 2 of the 4 coin families it supports, and then each of those two takes its own non-default detour afterward." BTC/DOGE/DASH ignore BIP39's machinery from the start.

Why the Electrum import produced a different address

Electrum is a different wallet app entirely — it doesn't read ADAMANT's code, it just assumes any 12-word phrase you type in follows the industry-standard recipe called BIP39. That recipe runs the words through a much heavier process before it ever becomes a private key:

seed = PBKDF2-HMAC-SHA512(mnemonic, salt="mnemonic"+passphrase, 2048 rounds)
master_key = BIP32_from_seed(seed)
private_key = derive(master_key, "m/44'/0'/0'/0/0") # or similar

In plain terms: Electrum stretches the words through a slow hashing process 2,048 times over (PBKDF2), then uses the result to build a whole tree of possible keys (BIP32), then picks one specific branch of that tree (the m/44'/0'/0'/0/0 "path"). That's a completely different pipeline from ADAMANT's single, direct SHA256(passphrase).

Neither approach is "wrong" cryptographically — they're just incompatible standards, like two people using different formulas to convert the same word into a number. ADAMANT rolled its own, simpler scheme instead of using BIP39/BIP32, which means BIP39-aware wallets like Electrum can never reproduce an ADAMANT-derived address from the same words, even though both are valid, deterministic, passphrase-derived keys.

That's an important nuance for anyone auditing "self-custodial" claims: the absence of BIP39 compatibility isn't itself proof of custodial risk — the passphrase-derived key is still generated and held entirely client-side. But it does mean you can't use a generic wallet as an independent cross-check the way you normally could. You have to speak the app's own derivation dialect.

A notable design detail: address reuse across coins
Digging one level further, in src/lib/bitcoin/networks.js:

const nets = {
[Cryptos.DOGE]: coininfo.dogecoin.main.toBitcoinJS(),
[Cryptos.DASH]: coininfo.dash.main.toBitcoinJS(),
[Cryptos.BTC]: coininfo.bitcoin.main.toBitcoinJS()
}

getAccount() is shared across BTC, DOGE, and DASH — meaning the exact same 32-byte private key (SHA256(passphrase)) is reused for all three chains. Only the network version bytes differ (via the coininfo library), which changes the address encoding, not the underlying key. That's a legitimate, common pattern for multi-chain wallets built on secp256k1 (same curve, same private key, different address prefixes) — but it's worth knowing, since it means compromising the BTC key compromises DOGE and DASH funds too.

Part 2 — Proving it yourself

Reading the code and understanding the algorithm is most of the work, but it isn't the proof yet. Anyone can read getAccount() and say they understand it — the actual "trust but verify" moment is writing a second, completely independent implementation of that same math, from scratch, using none of ADAMANT's own code, and checking whether it produces the exact same address ADAMANT shows you. If it does, that's real, checkable proof the key really is computed client-side from your passphrase alone — not proof by reading, proof by reproducing.

Why write a second implementation instead of just trusting the read-through


Reading code can mislead you in ways that are easy to miss: a function could look correct but never actually get called from the real account-creation flow, there could be a second, different code path used in production, or a subtle bug in my reading of the JavaScript could go unnoticed. An independent reimplementation sidesteps all of that — it either produces the address you see in ADAMANT, or it doesn't, with nothing left to interpretation.

Setting up

The script uses the same three public libraries ADAMANT's own code depends on (bitcoinjs-lib, ecpair, tiny-secp256k1) — reusing the well-tested cryptography those libraries provide is reasonable and doesn't undermine the independence of the test, since the whole point is to verify how ADAMANT calls them, not to reinvent elliptic curve math from first principles. What matters is that none of ADAMANT's own source files are imported or reused.

mkdir adamant-btc-verify && cd adamant-btc-verify
npm install bitcoinjs-lib ecpair tiny-secp256k1

That downloads just those three packages (and their own dependencies) into a fresh, empty folder — much faster than a full npm install inside the cloned ADAMANT repo, which would pull in Electron and hundreds of unrelated packages for the full app.

The script

import * as bitcoin from 'bitcoinjs-lib'
import { ECPairFactory } from 'ecpair'
import * as tinysecp from 'tiny-secp256k1'
import readline from 'node:readline'

const ECPair = ECPairFactory(tinysecp)

// Reads a line from the terminal without echoing it back to the screen, so your
// passphrase never appears in your terminal's visible output or scrollback.
function readPassphraseHidden(promptText) {
return new Promise((resolve) => {
const rl = readline.createInterface({ input: process.stdin, output: process.stdout })
process.stdin.on('data', (char) => {
char = char.toString()
if (char === '\n' || char === '\r' || char === '') return
process.stdout.clearLine(0)
readline.cursorTo(process.stdout, 0)
process.stdout.write(promptText + '*'.repeat(rl.line.length))
})
rl.question(promptText, (value) => {
rl.close()
process.stdout.write('\n')
resolve(value)
})
})
}

const passphrase = await readPassphraseHidden('Paste your ADAMANT passphrase (hidden): ')

// ---- This block is the exact algorithm from getAccount() in btc-base-api.js ----
const network = bitcoin.networks.bitcoin
const pwHash = bitcoin.crypto.sha256(Buffer.from(passphrase))
const keyPair = ECPair.fromPrivateKey(pwHash, { network })
const address = bitcoin.payments.p2pkh({ pubkey: keyPair.publicKey, network }).address
// ----------------------------------------------------------------------------

console.log('\nDerived BTC address:', address)

Two deliberate safety choices worth calling out, since this script is handling real key material even though it's just a learning exercise:

The passphrase is never echoed to the screen. readPassphraseHidden() intercepts each keystroke and redraws the line as asterisks instead of letting the terminal print what you typed — the same idea as a password field on a website, just implemented by hand since Node's built-in readline doesn't hide input on its own.

The private key is never printed, logged, or stored anywhere. Only the final address is shown. The address alone is sufficient proof (it's what you compare against ADAMANT's own display); there's no reason a verification script should ever need to reveal the actual secret it computed along the way.

Running it

node verify-btc-address.mjs

The script prompts for a passphrase, computes the address, and prints it:

Paste your ADAMANT passphrase (hidden): 
Derived BTC address: 1JTpYrn6TWYjgwk3...
That address is then compared by hand against what ADAMANT itself shows under Wallet → BTC.

The result

They matched. Running an independent, from-scratch implementation of the same three lines of math — SHA256(passphrase) → private key → P2PKH address — using different code, on a different machine process, with no connection to ADAMANT's app whatsoever, produced the identical Bitcoin address ADAMANT displays for that same passphrase.

That's the actual proof this whole post has been building toward: the BTC key isn't generated on a server, isn't something ADAMANT's company could quietly recreate or withhold, and isn't hidden behind proprietary logic. It's fully determined by one thing — the passphrase — and computable by anyone who reads the (public, open) source code closely enough to reimplement it. That's what "non-custodial" is supposed to mean, and now it isn't just a claim on ADAMANT's website — it's something checked, independently, end to end.

One more nuance: non-custodial isn't the same as portable

It's tempting to stop at "the address matched, so this is fine" — but there's a real cost to ADAMANT's custom derivation scheme that a match test alone doesn't capture: you can only recover these funds using ADAMANT's own software. A standard BIP39 wallet's whole selling point is that your 12 words work in any compliant wallet — Electrum, Sparrow, a hardware wallet, whatever you want, forever, even if the original company disappears. ADAMANT's passphrase only ever produces the right BTC address inside ADAMANT itself (or a from-scratch reimplementation like the one above). If ADAMANT the project ever shuts down and nobody's kept a copy of this derivation logic, recovering those funds gets a lot harder — not impossible (the algorithm is public, in the open-source repo, forever, as long as someone can find and run it), but nothing close to "type your words into any wallet."

That's a genuine, separate axis from custody, worth being clear-eyed about: your funds are non-custodial, but not portable. Checked WalletScrutiny's own definitions for both (custodial.yml and the hd entry in features.yml) — the custody question is narrowly "does the provider hold your keys," which ADAMANT passes cleanly, while the portability question already has its own, separate feature flag (hd), which correctly isn't claimed for ADAMANT here. Two different questions, two different answers, and it's worth asking both about any wallet, not just the custody one.

Takeaways

  • "Non-custodial" claims are verifiable, not just trustable — the actual proof lives in a handful of lines of derivation code, and it's provable by reproducing it independently, not just by reading and nodding along.
  • Finding that code is a search problem before it's a reading problem: grep for the vocabulary (bip39, bip32, hdkey, sha256, fromPrivateKey) before opening files. Any wallet's derivation is a small, greppable target inside a much larger app.
  • A failed cross-wallet import (e.g. ADAMANT → Electrum) is not automatically a red flag — it can simply mean the app uses a non-standard (non-BIP39) derivation scheme. The mismatch is a clue to keep digging, not a verdict on its own.
  • Don't trust a wallet's own vocabulary. ADAMANT calls its seed phrase a "passphrase," which collides with the actual BIP39 term for a completely different, optional thing (an extra user-typed secret on top of a seed phrase). Always confirm what a word means in this specific app's code, not what it means industry-wide.
  • "Does this wallet use BIP39" can be true for some of its coins and false for others, in the same app, from the same 12 words. ADAMANT's BTC/DOGE/DASH skip BIP39's seed step entirely; ADM and ETH use it, then each diverges from the standard afterward in its own way. Check every coin's path separately — don't generalize from one.
  • Non-custodial and portable are two different questions with two different answers. ADAMANT passes the first cleanly and fails the second — funds are genuinely self-controlled, but only recoverable through ADAMANT's own (open-source) code, not any standard wallet. Ask both questions about any wallet you're evaluating.
  • When writing a verification script that touches real key material, treat it like it matters even in a "just learning" context: hide passphrase input, never print or log the private key, only ever surface what's needed to prove the point (here, just the resulting address).

Friday, November 24, 2023

EventId's in Nostr - from CGPT4

The mathematical operation used to derive the event.id in your getSignedEvent function is the SHA-256 hash function, applied to a string representation of the event's data.

async function getSignedEvent(event, privateKey) {
          var eventData = JSON.stringify([
          0,            // Reserved for future use
          event['pubkey'],  // The sender's public key
          event['created_at'],  // Unix timestamp
          event['kind'],    // Message "kind" or type
          event['tags'],    // Tags idnetify replies/recipients
          event['content']  // Your note contents
          ])
          event.id = sha256( eventData ).toString( 'hex' )
          event.sig = await schnorr.sign( event.id, privateKey )
          return event
       }        

Let's break down this process:

String Representation of Event Data:

First, a string eventData is created from the event object. This string is a JSON representation that includes several fields of the event object, such as the sender's public key (event['pubkey']), timestamp (event['created_at']), message type (event['kind']), tags (event['tags']), and content (event['content']).

These fields are combined into an array and then serialized into a JSON string.

Applying the SHA-256 Hash Function:

The SHA-256 hash function is then applied to this string. SHA-256 stands for Secure Hash Algorithm 256-bit and is a member of the SHA-2 cryptographic hash functions designed by the NSA.

Cryptographic hash functions like SHA-256 have several key properties:

  • Deterministic: The same input will always produce the same output.
  • Fixed Size: Regardless of the input size, the output (hash) is always of a fixed length. In the case of SHA-256, the output is 256 bits (32 bytes) long.
  • Fast Computation: The hash value is quick to compute for any given input.
  • Pre-image Resistance: Given a hash value, it's computationally infeasible to find the original input.
  • Small Changes in Input Produce Significant Changes: Even a tiny change in the input will produce a significantly different output.
  • Collision Resistance: It's extremely unlikely (though not impossible) that two different inputs will produce the same output hash.

Creating event.id:

The output of the SHA-256 hash function (applied to eventData) is then converted to a hexadecimal string. This hex string becomes the value of event.id.

This event.id serves as a unique identifier for the event, and due to the properties of the SHA-256 hash, it also ensures the integrity of the event's data. Any change in the event's data would result in a completely different event.id.

In summary, the event.id is derived through a process of serialization (converting the event data to a JSON string) and hashing (applying SHA-256 to this string). This process is fundamental in many cryptographic applications, including blockchain and digital signatures, as it ensures data integrity and uniqueness.

Monday, August 07, 2023

The Change We Deserve Comes at a Steep Price




At 41 years of age, I am starting to become a grumpy old man. So when I saw people on FB "debating" how the Germans can do this, I start to philosophize about how we are, as we are today. What made the Germans and the Japanese so orderly? I am sure that some young one, would be studying these cultures as a topic of their thesis some day. 

I replied to the FB thread and posited a challenge and a rhetorical question: 

I'm happy that we are discussing this. It's a little bit of social science and a little bit of philosophy.

I've been following some Japanese "shorts" showing how orderly Japan is, and marveling at how they do that as well.

Among the answers I found here are:
  1. Law enforcement
  2. Discipline - with some dissent
  3. Culture - with some reservations
  4. Fines
  5. Education
I would offer the notion that it's all of the above. Now, if we combine these 5 ideas, we'll actually get to the bottom of this.

The problem with **law enforcement** is the sheer number of **undisciplined** people in our country. The **culture** of **corruption** is deeply ingrained, that **fines** are subverted because **corruption** allows people to make bribes. Our **education** system has also been **corrupted** because all that is being taught today, is to get out of the country so that "you'll make it.". **Law enforcement** is also difficult because our **leaders** are not accountable. They are often exempted. The mass **culture** is of personal gratification rather than collective responsibility. More often than not, the defense of errant drivers is **what about that guy**. Or, what about politician X, who did not even pay estate tax. ad infinitum. 

So here are the boldest questions: the change we need is going to be tough. It has to be cultural. And it will require changes.

Are we really ready for the change that we need?
Do we really even want to change?

Have a pleasant morning to all of us.

P.S. Lawrence Celestino - you really remind me of my younger self. I hope you are successful in your - in **our** dream of an orderly society. The question really is - what is the next BIG STEP? Is it still possible given the leadership we currently have?

Are there people willing to risk their lives to make this happen? Because, as you have said - people are violent. That is true.

Friday, December 23, 2022

c++ study notes

 terms: flooding network propagation


--- cpp


statement - type of instruction that causes the program to perform some action.


function - a collection of statements that execute sequentially


Declaration statements

Jump statements

Expression statements

Compound statements

Selection statements (conditionals)

Iteration statements (loops)

Try blocks


####################

Rule


Every C++ program must have a special function named main (all lower case letters). When the program is run, the statements inside of main are executed in sequential order.

####################


preprocessor directive

#include <iostream>


{

function body

}


// single line comments

/* multiple line comments */


data is any information that can be moved, processed, or stored by a computer.


 value - a single piece of data stored somewhere


In C++, direct memory access is not allowed. Instead, we access memory indirectly through an object. 


An object is a region of storage (usually memory) that has a value and other associated properties


 A named object is called a variable, and the name of the object is called an identifier.


runtime - when the program is run


instantiation - object is created and assigned a memory address


variable - a named region of memory


identifier - name that a variable is accessed by


type - tells the program how to interpret a value in memory.


copy assignment / assignement = after a variable has been defined, you can give it a value 


= assignment operator


initialization - variable defined and provided an initial value


initializer - the value used to initialize a variable


4 ways to initialize


int a; // no initializer

int b = 5; // initializer after equals sign - copy initialization

int c( 6 ); // initializer in parenthesis - direct initialization

int d { 7 }; // initializer in braces


copy initialization - when initializer follows an equal sign

direct initialization 

brace initialization/uniform initialization/list initialization


 3 kinds of brace initialization

 - int width { 5 }; // direct brace initialization of value 5 into variable width (preferred)

 - int height = { 6 }; // copy brace initialization of value 6 into variable height

 - int depth {}; // value initialization (see next section


value initialization and zero initialization

- variable initialized with empty braces

- value assigned is 0

- zero initialization



Initialization gives a variable an initial value at the point when it is created. Assignment gives a variable a value at some point after the variable is created.


Direct brace initialization.


<< - insertion operator - cout


>> - extraction operator - cin


using namespace std; - "using directive" avoid


std::endl vs ‘\n’


######

Best practice


Prefer ‘\n’ over std::endl when outputting text to the console.

######


_____1.6


- initialization - object given value at the point of definition

- assignment - object given value beyond the point of definition

- uninitialized - object not given a known value yet


always initialize your variables


Undefined behavior - executing code whose behavior not well defined in c++


_____1.7 


keywords - 92 words reserved by c++ for 

identifiers - override, final, import, and module.


ide changes color to blue of these words


c++ is case sensitive


always start lowercase

not number

no symbols

no space

no reserved words


snake_case

camelCase or interCapped


######

Best practice


When working in an existing program, use the conventions of that program (even if they don’t conform to modern best practices). Use modern best practices when you’re writing new programs.

######


_ underscores - OS, library, and/or compiler use


correct (follows convention)

incorrect (does not follow convention)

invalid (will not compile)


_____1.8 Whitespace


_____1.9 Literals and operators


literals or literal constant - fixed values inserted into source code


arity, the number of operatands an operator takes as input


- unary

- binary

- tertiary


_____1.10 Expressions


Expression

An expression is a combination of literals, variables, operators, and function calls that can be executed to produce a singular value. 


Evaluation 

The process of executing an expression is called evaluation, 


Result

and the single value produced is called the result of the expression.


_____2.1


function = reusable sequence of statements to do a job

user-defined function = function that user writes himself

function call = an expression that tells the CPU to interrupt the current function and execute another function


caller = the function that initiated the function call

callee or called function = the function being called


### syntax to define a user defined function


return-type identifier() // identifier replaced with the name of your function

{

// Your code here

}


the curly braces identify the function body


###


metasyntactic variable - placeholder names


_____2.2


return value

return type 

return statement

return value


""""""

When you write a user-defined function, you get to determine whether your function will return a value back to the caller or not. To return a value back to the caller, two things are needed.


First, your function has to indicate what type of value will be returned. This is done by setting the function’s return type, which is the type that is defined before the function’s name. In the example above, function getValueFromUser has a return type of void, and function main has a return type of int. Note that this doesn’t determine what specific value is returned -- only the type of the value.


Second, inside the function that will return a value, we use a return statement to indicate the specific value being returned to the caller. The specific value returned from a function is called the return value. When the return statement is executed, the return value is copied from the function back to the caller. This process is called return by value.""""""


status code 

exit code

return code


DRY = Don't Repeat Yourself


_____2.3 Function parameters and arguments



function parameter - is a variable used in a function. 


A function parameter is a variable used in a function. Function parameters work almost identically to variables defined inside the function, but with one difference: they are always initialized with a value provided by the caller of the function.


argument - value that is passed from the caller to the function when a function call is made


pass by value - parameters of the function created as variables, value is copied


//This is a hard topic, learn more about passing of value


**function prototyping


_____2.4 Local scope


Function parameters, as well as variables defined inside the function body, are called local variables (as opposed to global variables, which we’ll discuss in a future chapter).


An identifier’s scope determines where the identifier can be accessed within the source code. When an identifier can be accessed, we say it is in scope. When an identifier can not be accessed, we say it is out of scope.


_____2.5 Why functions are useful and how to use them effectively


- organization

- reusability

- testing

- extensibility

- abstraction


refactoring - when a function is split into multiple sub-functions 


_____2.6 forward declarations


A forward declaration allows us to tell the compiler about the existence of an identifier before actually defining the identifier.


function prototyping - a declaration statement. Is composed of 


    - return type

    - name

    - parameters



#### ODR #####


One Definition Rule


1. Within a given file, a function, object, type, or template can only have one definition.

2. Within a given program, an object or normal function can only have one definition. This distinction is made because programs can have more than one file (we’ll cover this in the next lesson).

3. Types, templates, inline functions, and variables are allowed to have identical definitions in different files. 


Declaration - a statement that tells the compiler about the existence of an identifier and its type information. 


in C++ - all definitions are also declarations


but not all declarations are definitions


Pure declarations - "An example of this is the function prototype -- it satisfies the compiler, but not the linker. These declarations that aren’t definitions are called pure declarations. Other types of pure declarations include forward declarations for variables and type declarations (you will encounter these in future lessons, no need to worry about them now)."


Function prototype - A function prototype is a declaration statement that includes a function’s name, return type, and parameters. It does not include the function body.


Forward declaration - A forward declaration tells the compiler that an identifier exists before it is actually defined.

 - according to Bucky this is actually called "Function prototyping"


Notes:


Compiler fails to compile if function does not have the same number of parameters.


Other compiler link problems - if a function is undefined (no body), linker can't resolve the function call.  


Violating ODR rule 2 - "Within a given program, an object or normal function can only have one definition"


_____2.8 naming collisions and namespaces


:: in std::cout - scope resolution operator 

The identifier to the left of the :: symbol identifies the namespace that the name to the right of the :: symbol is contained within. If no identifier to the left of the :: symbol is provided, the global namespace is assumed.


using directive - (using namespace std) -  tells the compiler to check a specified namespace when trying to resolve an identifier that has no namespace prefix


_____2.9 introduction to the pre-processor


Prior to compilation, program goes through translation.


Translation has many phases.


Preprocessor directive (or simply directive) scans from top to bottom of file. Start with # and end with a new line.


Macro defines 


a macro is a rule that defines how input text is converted into replacement output text.


object-like macros

function-like macros


Object-like macros can be defined in one of two ways:


#define identifier

#define identifier substitution_text


When the preprocessor encounters this directive, any further occurrence of the identifier is replaced by substitution_text. The identifier is traditionally typed in all capital letters, using underscores to represent spaces.


Tuesday, April 05, 2022

Fatherhood is like...

 Having a JP Drain stuck on your tummy and with people harnessed while you try to climb a mountain.

Wednesday, November 24, 2021

Trying to Install c-lightning

In my work with walletscrutiny.com, I had to test an app called Spark Wallet. The app needs a c-lightning node, which means installing c-lightning.

Several issues cropped up. 

One, the instructions given here, are for Ubuntu, and not for Linux Mint, which is the machine I'm trying this. 

Issue 1: 

sudo add-apt-repository -u ppa:lightningnetwork/ppa

does not work. No such option as -u

I removed the -u and it worked.

Issue 2:

gpg: keyserver receive failed: General error

Issue 3:

Package 'snapd' has no installation candidate
Fixed by moving a file that causes the restriction, which enabled snap.

2021-11-24 Installing Bitcoin-Core

Friday, August 27, 2021

How to find Private Key in Mycelium Bitcoin Wallet

1. Accounts Tab > My HD Accounts

2. Three Dots

3. Export

4. Show Private

* BIP32 Root Key Shows Up, starts with xprv

5. Use Mnemonic Code Converter - Recovers HD Wallet using mnemonic keywords

    a. Download/access here:

        https://iancoleman.github.io/bip39/ >> redirects to:

        https://iancoleman.io/bip39/


7. Copy BIP32 Root Key shown in the wallet

8. Paste in the "BIP32 Root Key" field

9. Click on BIP32 TAB, Under Derivation Path

10. Shows BIP32 Extended Private Key field.

Source: Reddit

Saturday, July 24, 2021

TheNewBoston.com Blockchain and Cryptocurrency Project


2.6 million people know Bucky Roberts. 

There are 481,000,000 views on his youtube channel. 

What he started has caught on like wildfire.

What did Bucky Roberts do?

P.S. This is not Bucky Roberts

Coding Tutorials

It all began with simple coding tutorials on YouTube. It started sometime in 2008 with a tutorial on XHTML. From there, it branched out to Photoshop, Dreamweaver, Adobe Flash, CSS, Adobe Illustrator, Javascript, Web Design, E-Commerce, PHP, C++, How to Build a Computer, Robotics Electronics, Python, Java, Adobe After Effects, Game Development, 3DS Max, Blender, Assassin's Creed Walkthroughs, --- and more.

He also ran a vlog where he talked about any topic he thinks about. By 2010, thenewboston was starting to take shape as a podcast and later on - a social media network

Everything seemed to be on the up and up, but then sometime between 2015 to 2020, Bucky went on an unannounced sabbatical. 

Where in the World is Bucky Roberts?

People missed him so much that you could find entire threads about "Where is Bucky Roberts now?" littered all around the Internet:

Work and Penguin Chess




Hello World - Bucky Roberts Comes Back


After a lot of speculation, Bucky uploads "Hello World" on Nov. 6, 2021.



Sunday, July 11, 2021

Creating Freecodecamp Tribute Page


I started getting back into my freecodecamp.com HTML and CSS tutorials. When I started in 2017, I figured that it's something that I could use. I guess, back then I wanted to put up my own business startup. Nowadays when I send a job application to some companies on LinkedIn, I can't help but be skeptical. 

Practically anybody who can think of a cool name, think of a clever dot com domain, could "pretend" to be a legitimate company. 

I'm still grappling with this idea of remote businesses - since they could be prone to abuse. As you get older, you tend to get more cautious. 

Friday, June 11, 2021

Stepping on Broken Glass

One of the things I've learned as I soon reach my 40's is that blogging can be a bit like stepping on shards of glass. And no, it won't be like some Tony Robbins spectacle. It can be excruciating. Unresolved reasoning plus the dawning of a reality that is not as rational as we'd hope to be clouds the mind. This lends the blogger, some dangerous hesitation. Social media, with all the events that transpired has shown the variety of opinions that are proliferating in the wild. Like a goat's diarrhea, the blogger can be put-off from sharing his thoughts out of fear for real-world consequences that can have a direct impact on your physical wellbeing. As I watch the transformation of social discourse across various mediums, each and every one of us fits into a certain mold. Stereotypes. We say what we say, because of our background, our upbringing, education, exposure and experiences. It's very rare to transcend that. It takes a huge amount of intellectual humility to come to grips that even imperfect opinions have a set of eyes and a brain with its own experiences, with its own background and with its own categories. This is where silence can become a weapon. In an age of inundation, sitting down cross-legged with eyes closed can be a welcome refuge from the circus that social discourse has become.

Sunday, April 04, 2021

Happy Easter

I Quit My Job

  • Happy Easter
  • I quit my job after 37+ days.  
  • I wish boss the best. 
  • I'm going to try and look for another job again. 
  • Gives me enough freedom to work on getabunkernow.com
  • NCR+ Covid cases now reaching an average of 10,000+ daily
  • My cousin (Who's a doctor) said, people were busing in patients from Manila to the provinces (Lipa City hospitals are full)
  • Ukraine, Russia,and NATO tensions are rising. 
  • Still need to finish the bunker website.
  • Need to plant more papayas
  • Security concerns. 
  • Pastor of V church, positive for Covid
  • Thinking of getting a ham radio
  • Many second hand in Facebook
  • People manning the checkpoints here - are basically useless, until they get further orders

Random Thoughts of a Loose Cannon

  • 4th wave of Covid possible for US
  • NCR+ is back to Enhanced Community Quarantine
  • Almost finished with the survival bunker website.
  • Made a lot of tweets hopefully to find successful candidates
  • Wrote an article for CMC, still waiting for feedback
  • Learning more about blockchain via Julien Klepatch on EatTheBlocks - I like the guy. 
  • Connected with a Filipino blockchain developer, B.L. on Linkedin. He's also a farmer!
  • Restyled the blog to look oh so retro
  • Haven't been able to read the Tagalog Bible for quite some time. 
  • It's harder to write honestly now. 
  • Blockchain Covid Passports - Revelations 13. Patent 2020060606
  • The Mark of the Beast was trending earlier this day.
Most of the things I seem to be unrelated. But somehow, through some weird connection, I believe they are. Writing for cjl pays for the daily expenses. The spare money goes to the farm. If the situation turns for the worst, we'll have food - well papayas and kamote. Once I sell a bunker, I would be able to make some much-needed repairs and upgrades to the farm. 

On religion and spirituality

  • Is it appropriate or "good" to have copy-paste faith? 
I have some friends on social media who seem to be so sure of certain beliefs. But most of the things they share are copy-pasted. I understand that not everyone can be articulate especially on matters of faith. I don't even know if it was in response to my post about the Jewish Revolt. 

The Jewish Revolt

Jesus Christ died either on 30 AD or 33 AD. He was crucified by the Romans out of allegations that he committed the crime of blasphemy. A charge that Jewish religious leaders were intent on leveling against him. 

Friday, March 26, 2021

DeFi Jobs and Bitcoin Maximalism

Decentralized Finance or DeFi is a topic of interest for me mainly because it has to do with my current employment. The prospect of DeFi-Jobs created with the advent of a new sector enthralls many in the cryptocurrency industry. But Robert Farrington of Forbes.com, captures the attitude of many when he said, 

"If you're not into cryptocurrency, then the mere mention of Bitcoin or Ethereum probably makes you want to roll your eyes."

 Many detractors from within the cryptocurrency community can also have aversions to DeFi, primarily

The reasons for these are diverse. In my foray into the world of Crypto Twitter, there is such a thing as "Coin-Envy" and "Coin-ism". Perhaps the best term for this behavior is Bitcoin Maximalism. It stems from a belief that only Bitcoin (BTC) is the sole cryptocurrency that bears any significance both in technical and ideological aspects. 

Monday, February 22, 2021

Why Buy a Survival Bunker at TerraVivos

 

terra vivos xpoint survival bunkers

One word: location

TerraVivos luxury survival bunkers are the optimal survival solution for you and your loved ones. 2020 has shown us that things can get out of hand in fast succession without any warning and without any reservation. 

Unlike other fortified structures, Terra Vivos understands the global risks and prepared for it by selecting the best location that minimizes risk. 

Let's be honest for a moment - most people were not prepared for the COVID19 pandemic. Governments all over the world quarantined entire cities. They placed entire nations under lockdowns and effectively made the world isolated from each other. 

So I took a look at Vivos location and found it ideally isolated from most of the high-risk areas in the United States. 

terra vivos xpoint survival bunkers

Building a Community in a Secured Location
News that Apophis or some other asteroid may be visible from Earth soon has people fantasizing about whether it could somehow collide with the planet. Discovermagazine.com says it won't but the existence of NEOs or (Near Earth Objects) or some recent near misses that were previously undetected - the possibility is real. 

How long would you wait to prepare before it happens?

The need to find a location to shelter during a mass extinction event or massive casualty scenario, is increasing in urgency. The pandemic is still ongoing despite the creation of vaccines. The most salient threat to a return to 'normalcy' are mutations and the increasing prevalence of other diseases such as the bird flu and Ebola variants. 

Once you have secured your bunker and your supplies, the next threat would be protecting your supplies. This is Vivos. 


You can join Terra Vivos by visiting getabunkernow.com



Tuesday, January 19, 2021

Inundated

The good thing about blogspot blogs is that they retain a semblance of semi-permanence. A decade can pass and you'd still have those things in the past clinging to you as if to remind you. 

Not unless, your content gets banned and you're taken down. 

So many things have changed online and offline. 

Note that I'm writing for some wayward researcher in the future, who happens to stumble upon this blog for some reason. Content 50+ years into the future. Okay, maybe 10. 5?

First the Internet is no longer about the geeks, it's about everybody. I needed to get that off my chest. I used to think that this could be good for everybody, but I have since then changed my mind. Having everybody on the Internet is not a good idea.

Donald Trump, a prominent real estate Baron, became the 45th President of the United States. And, he went down amidst a cacophony of shame, division and enmity. Wikipedia it, if that still exists in your time. 

In the Philippines, Rodrigo Duterte would impose a very complicated presidency. I'm not going to comment on that any further, just read Rappler and compare its accounts with that of The Manila Times. Take your pick.

Meanwhile, I have since had to adapt my writing style to be more... opaque. Given the current climate of intolerant tolerance and sensitive powers-that-be, I have to calibrate words to make my thoughts more uninteresting. 

I still don't have the domain. Some gook (and yes, that is a politically incorrect disparaging word) bought it for some reason, most likely to annoy me. 

A global pandemic, which I'm sure would be very boring 50 years from now, has turned the wonders of having everyone on the Internet into a frigid nightmare of a wasteland. Everybody gets to stay home and post their issues online be it one way or another. 

In 2021 and it's sooooo much easier to get clicks and views on ads, but 95% of these are people who have absolutely nothing to do but to look for guys selling something on Facebook annoyed. Back then, maybe about 5 to 10 years ago, the problem was nobody looked at your ad. Now everybody you don't want to looks at them. And they say pretty much the same thing:

HM?

Last Price?




Saturday, October 06, 2018

The Precipice

Photo by Eric Welch on Unsplash

I vividly recall walking along the overpass that connected the Maharlika, the Igorot park and Sunshine grocery in Baguio City. This was in the early 2000's. Donning a maong jacket, I savored the mixture of the cool Baguio breeze, the distinct Baguio market smell, the cigarette smoke of some pedestrians and carbon monoxide wafting from the jeepneys below. This is where I saw many a crowd transfixed on their own journeys unmindful of the events and actions of others - until it touched them.

The lady in front was wearing a backpack. Behind her were two short male teenagers with unkempt hair. I could tell that they were from further up North. The hairstyle was quite common up there. Yung parang bunot and with the Star Wars like small hair braid at the side of the ear. Parang ayaw ata nila sa mga barbero. They also kept their bell bottom like dirty maong pants long and wore slippers despite the edge of their pants touching the ground. They also wore those leather vests or jackets that made them look like, well, let's be blunt here, poor cowboys.

They opened the bag of the lady as if in rhythm with the movements of everybody. You'll only notice if you're mindful. Slowly, they got the wallet out with nobody noticing - except me. Tired from a full load in the University of the Philippines Baguio, and hoping that I would get home in time, I was annoyed.

I was annoyed because I felt that I needed to to do something.

While they pocketed the wallet, I remembered that Sunshine had security guards posted near the overpass stairway. I followed the lady and the teens who were strangely still following their victim. At the precise moment when the lady, the teens and I were near the security guard, I held the jackets of the two and shouted at the guard and the lady at the same time. "Kinuha po nung dalawang eto ang wallet niyo. Mandurukot sila."

I was expecting a fight.

But the two were noticeably surprised and perturbed at the timing. Their eyes were wild-like, "We've been caught, oh no." They were partially immobilized by me but more because of the loud voice I commanded and the presence of armed guards.

I knew security guards didn't bother with these petty things (I have experienced this before and some really kept to their posts). But good enough that at the very least, he asked someone from the grocery to call the police. Wallet returned. No fight. Good. Pat in the back. Memories for me and something to write about after 17 or so years. That was my shortlived career as Batman.

Sometimes in my daily commute on that overpass, I'd read about a certain mayor from the far South and how he was linked to a certain group. In bold red letters, I would glimpse macabre headlines that seemed to exact a specific form of justice. Not the justice that we were taught in class or in the university, or the one by Plato, when he asks "What is justice?". This justice was the one some would say as the barbaric kind. The one that only God can exact on the transgressor.

"I wonder what it would be like if he would become President?" I'd mutter to myself.

Little did I know that my utterance would become a harrowing prophecy.

Fast forward to the future, where Facebook ruled, friends, relatives, strangers chimed for or against. They also posted some of those fist bumps. I wavered until the last day, when I voted for Mr. Palengke instead. Ugh. Would've voted for the Dark Horse for his humanitarian bent, in retrospect. But the smear campaign against him at the time, was really convincing.

My late father was historically connected to the Righteous Revolution of the 80's and was personally invited by the late Madam President. So, some of his friends would tarry on with practicing their essay writing skills on facebook where nobody would listen to their cliches.

These are different and difficult times.

Yeah, I agree with the principles of what you are saying since these are taught in most universities, textbooks, law books and even the Bible, but what solution do you propose? Wala.

"This is evil! He is Satan here on Earth!" My dad's friend would post.

Then my lola, (sister of my paternal grandfather) who I sometimes envision to be a vigilante herself, but is an old maid teacher instead would quarrel with this guy.

I know, I know, pero again, what solution do you propose?

I remember another one of my dad's friends, just in 2016. "People say this could be bad, this is wrong, but hey, look at it, 16,000,000 believed. I agree with everything you say. But God oftentimes does something that we don't understand. Maybe this bad thing, will lead to a good thing. Wouldn't your dad have believed the same and voted for him?"

"Nope. He wouldn't." I said.

The tools of the trade

I have a lot of junk wood that I keep around just in case. Sometimes, there would be difficult things in whatever carpentry thing I'm fixing and I would look around for some tool to help me. Sometimes, it was the darn worst of the worst thing, like an ugly piece of rock, or an imbalanced block of wood to help me. I'd try it. Sometimes it worked. Sometimes it didn't. But when it did work, after I've used it, I'd just put it back from wherever pile I got it from and mutter quietly, "You're ugly, but you did a better job than a wrench or a real tool. Thank you." Or something like that.

So, tonight, we're at the precipice caused by that ugly piece of imbalanced wood.

"If it's cancer, it's cancer."

Surprisingly, the first thing I felt was pity and sorrow.

He was that imbalanced piece of wood. Maybe, just maybe, despite him cursing God and all, he for all that has been said and done, dislodged something that had not budged for a long time. A lot of people in my Christian circle, swear by him.

One of them is an educator from Iloilo. Gotta remember Iloilo.

Come on, if that isn't proverbial, then what is?

One of the men who carried out this 'dislodging' was a man who had a name that sounds like the Spanish word for sword. I looked it up. Sword in Spanish is Espada. By all accounts, in the news, in TV, on YouTube, this man is the real deal.

And he spoke the Word.

Yeah, I can be that discerning every now and then.

But as it is... More changes are due

I really would like to stop making these pronouncements as they have a tendency to come true. But then, ah, it's too late, eh?

Yep, more changes are coming. Perhaps, not in the flavor we wish they would be.

I make it a habit to watch the news before going to sleep.

That's a really bad habit.

I do most of this on YouTube. I'd look at stupid viral things, read the comments -- and wish the old Internet would come back.

The Old Internet? Well, that's the Internet before non-geeks got their cheap smart phones and got Free Facebook. In short, the time when our generation was cool. The time when Yahoo! Free email! Free blogs! were first heard.

In short, that's the time when Google's motto was still Do No Evil.

It's strange reading the minds of everybody on something that should be crystal clear and unequivocal. This is after all, the era of nihilism, excess narcissism  fake news, historical revisionism and what not.

Many people really shouldn't be on the Internet.

It's mind pollution.

Saturday, July 07, 2018

The Presidential Question

Dear Mr. President,

I'm sorry to say Mr. President that I cannot give you a selfie picture with God.

I know that at your age, that you may be nearing the valley and that is why you are asking for the improbable, despite the strong need to address other more pressing worldly concerns.

If I could, Mr. President, I would.

But that is beyond me.

I can understand how you may be feeling right now. When my grandfather was about to die a couple of years ago from cancer, on his death bed, he made one wish, "that he could be young again - like a child."

It baffled our family during a very difficult moment.

But we all knew, that we can never turn back the hands of time.

We could not time travel to fix regrets, correct some mistakes we did and alter whatever it is that we have decided, done or what has been done to us in the past.

And that's part of the beauty of life - and death. There can only be one time that we could right all the wrongs, and that is the present.

Nobody could ever convince you Mr. President, if there is a God or not. No amount of logic could erase all the pain, all the regrets and all the questions and doubts floating in your head.

As it is, Mr. President, the same question is being asked by any child who is begging for alms in front of a church. The same question is being asked by the families of victims unjustly killed by an unrelenting state. The same question is being asked by the poor and the suffering. The same question is being asked by so many.

I am asking the same question too, but unlike you, I do not have the power to stop the killings and the murder. My words, are of so little consequence that they cannot temper the actions of men. I have no men who follow my orders, Mr. President. I cannot order anybody to, "Feed the poor. Clothe the naked. Love the unlovable. Stop the killings and bring justice for all."

But you have, Mr. President. You have that power.

Right now, a daughter is grieving the violent death of her father. She may be asking, "Where is God? Where is justice in all of these insanity?"

No righteous answers are given to her, Mr. President. Only words of pain, condemnation and anger.

"Your father was a drug lord, he has to die." is a sentence that keeps repeating again and again in her mind as they bury the dead tomorrow.

Words can bring life, justice, love, honor - but they can also bring death, destruction, pain and agony.

And tomorrow, these are the words that will be spoken:

The Lord is my shepherd; I shall not want. He makes me to lie down in green pastures; He leads me beside the still waters. He restores my soul; He leads me in the paths of righteousness For His name’s sake.

Yea, though I walk through the valley of the shadow of death, I will fear no evil; For You are with me; Your rod and Your staff, they comfort me.

You prepare a table before me in the presence of my enemies; You anoint my head with oil; My cup runs over. Surely goodness and mercy shall follow me All the days of my life; And I will dwell in the house of the Lord Forever.

Trust, But Verify: Reverse-Engineering a Wallet's Key Derivation

"Non-custodial" is a claim, not a fact. Any wallet can say your keys never leave your device — the only way to actually know is to...