-
Notifications
You must be signed in to change notification settings - Fork 205
Beam Technical Specifications
BEAM implements the MW protocol (with some extensions), which is based on elliptic curve cryptography (ECC).
Cryptographic primitives Cryptographic primitives used by BEAM are based on the secp256k1 library (the one that is used in bitcoin). Naturally it uses the same elliptic curve equation. The following primitives are used directly:
secp256k1_gej - Basic curve point arithmetics: point addition, doubling, negation, import/export to a platform-independent format. secp256k1_scalar - Scalar arithmetics: addition, multiplication, inverse secp256k1_sha256_t - SHA-256 hash Cryptographic nonce generation (nonce_function_rfc6979). secp256k1_hmac_sha256_t - HMAC (message authentication) The following cryptographic functions and schemes are built over them:
Point multiplication (by a scalar). There are different multiplication modes and scenarios: Secure/Fast Point may be either known in advance (a.k.a. Generator, prepared for multiplication) or "casual". Aggregation: when many points are multiplied by scalars and summed - an appropriate effective algorithm is used. The reason that this functionality is implemented in BEAM and not taken directly from secp256k1 is the following: We'd like to have more low-level control of the primitives to implement advanced schemes We need more generators: Standard secp256k1 supports just two (G,H), whereas we need hundreds No inherent implementation of the fast multiplication mode No effective aggregation implementation Commitments (encoded amount with the blinding factor) Schnorr's signatures (including multi-sig) Bulletproof (including multi-sig and batch verification) Secure communication channels Secure BBS Hash The Hash refers to the SHA-256 hash, unless otherwise specified. Used in various schemes. When hashing some data, it's fed in a way that is both platform-independent and unambiguous. This is achieved by the following specifications:
1-byte data is fed as-is Boolean values are encoded as a single byte with value either 0 or 1. Strings are fed as-is, including the 0-terminator (to prevent ambiguity for consequent strings). Numerical types (fixed-point) are stored as a variable-length byte sequence, with a special terminator mark. This ensures platform independence (integers may have varying width across different platforms). Non-primitive types are converted into the platform-independent binary format for hashing. The following objects are derive from hash (built over them)
Oracle Oracle is used in non-interactive cryptographic proofs, it's supposed to produce cryptographic challenges in a deterministic way, based on the visible transcript to the moment.
In BEAM Oracle uses the Hash in a straightforward way. All the visible transcript is hashed. Once the challenge is needed - the hash value is finalized, the result is the challenge, and it's immediately re-fed to the Hash. So that the new challenge construction (if needed) starts from the previously-produced challenge.
If there are restrictions for challenge (such as it should be non-overflowing, non-zero scalar, or a valid x-coordinate of a curve point) - the Finalize-Re-feed is called in a loop, until the satisfying challenge is produced (i.e. accept/reject strategy is used).
Nonce Generator Also used in cryptographic proofs, but, unlike Oracle, the nonce generation involves secret data, and should not be possible to reconstruct by others.
In BEAM Nonce generator is a combination of an Oracle, and the nonce function initialized by the secret data. That is, the Oracle accounts for all the visible transcript. When a nonce is needed - first it's received from the Oracle, and then passed as an input to the nonce function (implemented in (secp256k1), which also uses the secret data.
The final nonce generation function implemented in secp256k1 actually a modified HMAC-SHA-256 scheme.
KDF - Key derivation function All the private keys are generated via KDF. In BEAM it's implemented via the Nonce generator, which is initialized once by the master secret data. The requested key parameters (key index, type/subtype, etc.) are hashed and then the output is generated by the standard Nonce generator initialized with the master secret.
Schnorr's signature Implemented according to the standard, consists of a pair [e,k], whereas e is the challenge, and k is the blinded private key. Supports multisignature of course.
Specifically the scheme is the following. Given a message hash M, private key sk, public key pk = G * sk:
Prover Generate a nonce nk = Nonce(sk, msg), whereas Nonce() is the standard nonce generating function. Expose to Oracle: nkG, msg Get the challenge e from Oracle. Calculate k = nk - esk Signature: [e, k] Verifier Calculate P = kG + epk Expose to Oracle: P, msg Get the challenge e' from Oracle. Verify: e == e'
Binary platform-independent representation of the ECC primitives The following are the primitives:
ECC Scalar array of 256 bytes, representing the number in a big-endian format Deserialization ensures the number is indeed a valid scalar, i.e. strictly less than modulo-prime. This is to prevent ambiguity ECC Point Represented as an X-coordinate, and a Y-parity flag (1 bit). The X-coordinate is serialized in a big-endian format (similar to scalar). To recover the Y-coordinate one must solve a quadratic equation, which, naturally has 2 solutions. This is where Y-parity flag is used. Is serialized as-is the data is padded to a byte boundary (means the Y-parity bit takes the whole byte). However in some complex data types those flags are merged and stored separately (as in Bulletproofs). MimbleWimble objects in details The following are the objects:
Input UTXO reference Output UTXO Transaction kernel Input Represents a reference to an existing UTXO. Consists just of a commitment (a curve point). Nothing to discuss.
Output Represents a new UTXO that should be created by the specific transaction. Consists of the following:
Point: Commitment Boolean: Flag for Coinbase/regular uint64: Incubation period Signature: either public or confidential The "Incubation period" specifies the extra maturity (in addition to the system rules) for the UTXO until it becomes mature, i.e. may be spent in a transaction. It's exposed to the Oracle, which is used for the signature, to prevent tampering. The signature attached to the UTXO proves that:
The encoded amount is indeed within the allowed range: 64 bits The creator of the UTXO knows the opening of the commitment. Means - it's not a fake object. Signature does not reveal the UTXO blinding factor The signature can be either public or confidential, the appropriate must be attached according to the system rules. The rules are:
Coinbase UTXO must be signed with public signature, i.e. the encoded amount must be visible. Non-coinbase UTXO must be signed by confidential signature. The public signature is disallowed by default, but may be enabled in system configuration. Subject to design decision. Public UTXO signature Consists of the following:
uint64: The encoded Value. Schnorr's signature for the blinding. The prover exposes the Value to the Oracle, and then proceeds according to Schnorr's protocol to prove the knowledge of the private key, which is the UTXO blinding factor.
The verifier subtracts the Value*H from the commitment, this is the UTXO public key. Then exposes the Value to the Oracle, and proceeds according to Schnorr's protocol to verify the knowledge of the appropriate private key.
Confidential UTXO signature Consists of 16 Points and 5 Scalars, making it 674 bytes long. More about this later
Kernel The following are the fields
Mandatory Point: Excess Schnorr's signature Optional uint64: Fee uint64: Multiplier (more about this later) uint64 x 2: LockHeight Hashlock Contract Nested (inner) kernels In the simplest scenario contains just an excess point and a signature. The signature proves the following:
The preimage of the Excess (the scalar) is known to the kernel creator. The kernel wasn't tampered with after it was signed.
Transaction and Block validation Transactions and blocks have similar structure and validation rules
Transaction consists of the following:
List of input UTXOs List of input kernels (this is our extension to the classical MW) Lost of output UTXOs List of output kernels Scalar: Offset Block only uint128: Subsidy - total amount created by this block Boolean: SubsidyClose flag.
When a transaction/block is received, the following two types of validation are performed:
Context-free validation. Does not validate the existence of the referenced inputs Validates all the signatures and the overall arithmetics (more about this later) This is the most CPU-hungry part, but luckily it can be parallelized (more about this later) State transition Performs the state transition of the system wrt transaction/block, i.e. consuming the inputs and creating the outputs iff such a transition is valid according to the rules. This involves in particular verification that all the referenced inputs exist and mature enough The state transition is reversible, means it can be "played backward". This however requires saving some auxiliary information during the forward transition (more about this later). Context-free validation The following is checked:
All the output UTXOs and kernels are properly signed All the objects of the same kind (within a list) are specified in the lexicographical order Those kernels that contain LockHeight are verified vs current height. Transactions only: Coinbase output UTXOs are not allowed. The following is calculated:
Point: Sigma. Equals to the sum of all outputs minus all inputs. Defined as: Sigma = Σ(Output UTXOs) - Σ(Input UTXOs) + Σ(Output Kernels.Excess) - Σ(Input Kernels.Excess) + Offset * G Total Value of coinbase output UTXOs Total Fee value. Transaction-specific Transactions must not have the coinbase output UTXOs, and all the fees are considered lost, i.e. they are implicit outputs that should be added to verify the overall validity. Hence the final validation criteria is:
Sigma + Σ(Fee) * H = 0
Block-specific In blocks fees are already consumed (by the miner). To account for the block subsidy (mined coins) the validation criteria is:
Sigma - Subsidy * H = 0
In addition the verifier check that both the block subsidy conforms to the emission rules of the system, and that this amount is encoded within the Coinbase output UTXOs (means, the emission is not "hidden" in non-coinbase UTXOs).
Note that block in MW can be merged, so that the block being-verified may represent the state transition of multiple original blocks, with the appropriate height range. This must be accounted when checking the block subsidy and the values encoded with Coinbase UTXOs that are not spent yet. More about this later.
System state