## DEV Community is a community of 754,646 amazing developers

We're a place where coders share, stay up-to-date and grow their careers.

marpme (Marvin)

Posted on

# Stealth Addressing in depth [1/3]

First, we will start with the normal procedure which will occur on a daily recurring basis. This is a simple user-case situation where two individuals want to transact privately, as is their right. To do this, we need to a stealth address which makes it possible for the receiver to receive his funds from the paying person. Let’s call the payer Bob. For today’s text, we will cover the part on how to create a stealth address, and what it is made of, and what is it being used for.

## How to generate a stealth addresses?

First off you will need math, a lot of math. We basically need some crypto algorithms for this entire processes including SHA256, SECP256k1 (elliptic curve crypto with this equation y² = x³ + 7) and Base58 encoding.

The data structure of our stealth addresses:

`````` // [version] [options] [scan_key] [N] ... [Nsigs] [prefix_length]
``````

The overall structure of a normal stealth address is the following. It’s based on the version of the current stealth address, which simply specifies for which currency it could be used. If the version were to change, the blockchain would reject your address. The option is a simple unsigned integer, which can specify any options. You can a scan public key and multiple spend public keys (where N = number of keys; NSigs = all the spend keys) to send the funds to. The prefix length is by default zero.

Verge’s current version of the stealth address is 0x28.

### Step-by-Step creation of a verge based stealth address

1. Generate two private random numbers with a lenght of 32 bytes (aka. secure random numbers)
2. One will be declared as spend secret and the other as scan secret
3. each, scan and spend secret, will be used to generate a public key by utilizing SECP256k1 (length should be 33 bytes). Make sure to not overflow the SECP256k1 algorithm.
4. Now putting everything together into a single buffer in the abovementioned order.
5. Generate a hashsum of the current address buffer by double hashing this buffer with SHA256 and append the first 4 bytes of the checksum to the address buffer.

``````const { randomBytes } = require('crypto');
const secp256k1 = require('secp256k1');

// generates a private key from a secure/random source
generatePrivateKey = () => {
// generate privKey
let privKey;
do {
privKey = randomBytes(32);
// check if the seed is within the secp256k1 range
} while (!secp256k1.privateKeyVerify(privKey));

return privKey;
};

// generate a public key based on the current seeds
generatePublicKey = privKey => {
// get the public key in a compressed format
return secp256k1.publicKeyCreate(privKey);
};

const scanPriv = generatePrivateKey();
const spendPriv = generatePrivateKey();
// pass all the data into the stealth address class
scanPriv,
generatePublicKey(scanPriv),
spendPriv,
generatePublicKey(spendPriv)
);

``````

After this procedure, we have assembled the basic requirements needed to create a stealth address and we have gathered all the inputs needed. Namely having two pairs of keys (public and private) representing the scan and spend key. Those are needed to verify the transaction and signing them in new blocks. We will go in depth about that one later. First, we will cover the basics of stealth addressing.

With that being said, let’s finally create an encoded address by having a look at the stealth address class:

``````const stealth_version_byte = 0x28;
const crypto = require('crypto');
const bs58 = require('bs58');

constructor(scanPriv, scanPub, spendPriv, spendPub) {
this.scanPub = scanPub;
this.spendPub = spendPub;
this.scanPriv = scanPriv;
this.spendPriv = spendPriv;
this.options = 0;
}

encode() {
stealth_version_byte,
this.options,
...this.scanPub,
1, // size of public keys
...this.spendPub,
0, // size of signatures
0, // ??
]);

return bs58.encode(result);
}

generateChecksum(data) {
return crypto
.createHash('sha256')
.update(
crypto
.createHash('sha256')
.update(data)
.digest()
)
.digest()
.slice(0, 4);
}

validateChecksum(modules) {
const buffered = new Buffer.from(modules);
const checksumModule = buffered.slice(
buffered.byteLength - 4,
buffered.byteLength
);

const informationModules = buffered.slice(0, buffered.byteLength - 4);
const informationChecksum = this.generateChecksum(informationModules);
return {
valid: Buffer.compare(informationChecksum, checksumModule) === 0,
checksum: informationChecksum.toString('hex'),
};
}

let checks = this.validateChecksum(modules);
if (!checks.valid) {
return {
valid: false,
};
}

if (modules.length < 1 + 1 + 33 + 1 + 33 + 1 + 1 + 4) {
return {
valid: false,
};
}

checks = { ...checks, length: modules.length };

if (modules[0] !== stealth_version_byte) {
return {
valid: false,
};
}

checks = {
...checks,
stealthVersion: `0x\${modules[0].toString('16')}`,
};

return checks;
}

toJsonPrivate() {
return JSON.stringify(
{
scanPub: this.scanPub.toString('hex'),
spendPub: this.spendPub.toString('hex'),
scanPriv: this.scanPriv.toString('hex'),
spendPriv: this.spendPriv.toString('hex'),
options: this.options,
isStealth: this.isStealth(this.encode()),
},
null,
2
);
}

toJson() {
return JSON.stringify(
{
scanPub: this.scanPub.toString('hex'),
spendPub: this.spendPub.toString('hex'),
scanPriv: 'hidden',
spendPriv: 'hidden',
options: this.options,
isStealth: this.isStealth(this.encode()),
},
null,
2
);
}
};
``````

Okay, that was a big chunk for a read-through, focus on the path along the encode() method, which combines all the important buffers to one simple address buffer.

In the end, we will be covered with a checksum which is based on the address buffer. This will then merge with that address buffer, and give the possibility to verify if the address has been manually modified or corruption due to network failures, etc.

… to be continued : )

All the details explained over are based on the original idea of this stealth addressing workflow: