Table of contents
Signed mining
This article discusses the idea of signed mining, which tries to provide a safe construct with a high degree of delibration, in a Proof of Work blockchain system.
A good mining algorithm for a blockchain must ensure delibration. That is, it must enforce that partcipants on the network are carrying out the action of mining as a deliberate action. Put it simply, the owner of miners must be aware that they are mining, and miners must be aware that they are actively spending their resources. Deliberation makes it more likely that the fundamental assumption of honest majority holds, and thus less likely to be the subject of 51% attacks.
Absence of delibration leads to botnets and malicious browser-based mining. In all those cases, the owners of the hardwares are not aware that they are participating in the mining process. If a mining algorithm cannot prevent those types of issues, controllers of botnets may be able to obtain a large share of the network hashrate, and carry out attacks such as double spending.
Signed mining adds an additional requirement for mining hardware to hold the private key of coinbase of mining rewards. In this way, botnets and browser-based mining become much less efficient to carry out.
Basic
Signed mining can be applied to any nonce-based mining algorithms. Those mining algorithms can be generalized to expose the following function:
fn verify(pre_hash: Hash, nonce: Nonce, seal: Seal) -> bool;
pre_hash
is the hash of the header without PoW portion. nonce
is a
random number. The function verify
checks that pre_hash
and
nonce
evaluates to seal
, and the resulting seal is above a given
difficulty.
The mining process can then be expressed as follows:
loop {
let nonce = Nonce::random();
let seal = Seal::generate_from(pre_hash, nonce);
if verify(pre_hash, nonce, seal) {
return nonce
}
}
Signed mining proposes to add an additional signing together with the nonce:
fn verify_signed(
pre_hash: Hash,
nonce: Nonce,
signature: Signature,
seal: Seal
) -> bool {
signature.verify_with_message(pre_hash, nonce) &&
seal.verify_with_pre(signature)
}
pre_hash
and nonce
are first signed by coinbase key producing
signature
. The signature
is then fed into a normal nonce-based
mining algorithm to produce the seal. The signing process happens once
per nonce, and for mining, practically a large number of nonces are
always tried before a block is produced. As a result, this enforces
that mining hardwares must keep the private key together with the
miner. Transmitting large amount of signatures through the network is
impractical and inefficient.
Kulupu
This section describes a specification, with identifier 53-KSIGNED. (Discuss) |
Specification
Previously, an optional pre-runtime digest can be included in PoW
consensus engine, under POW_ENGINE_ID
. After signed minig, the
pre-runtime digest becomes required, and it encodes a sr25519 public
key, representing the coinbase author.
The header seal is changed to included an additional signature
field.
struct Seal {
difficulty: Difficulty,
nonce: H256,
signature: sr25519::Signature,
}
The RandomX work is computed as follows. First, we prepare the
Calculation
, using the block header pre_hash
, targeted difficulty,
and the chosen nonce.
struct Calculation {
pre_hash: H256,
difficulty: Difficulty,
nonce: H256,
}
The Calculation
is then encoded by SCALE, hashed by 256-bit
blake2b
to produce a hash. The hash is then signed by the coinbase
author sr25519 private key to produce a signature.
Then we encode (Calculation, sr25519::signature)
using SCALE, and
feed it as the input to the RandomX hashing function to produce the
final mining work.
Ethereum
This section describes a specification, with identifier 52-ESIGNED. (Discuss) |
Specification
Replace the coinbase
field of block header by r
. Add two new
fields into the block header, v
and s
. Together, v
, r
, s
hold an secp256k1 signature, whose public key is interpreted as the
new coinbase address for a block.
When verifying the Ethash PoW for a block, change the logic to be the following:
-
Given a header, get the hash \(H_1\) where
v
equalsCHAIN_ID
.r
,s
andmixHash
equals0
. -
Check that \(H_1\) is the valid preimage of the signature consisting of
v
,r
ands
, withv
equal toCHAIN_ID * 2
or
35CHAIN_ID * 2 + 36
. -
Calculate hash \(H_2\), with
mixHash
set to0
in the original header. -
Check that \(H_2\) is the valid preimage for Ethash of
mixHash
andnonce
.