Creating a simple cryptocurrency: part 3

in #cryptocurrency7 years ago (edited)

Accounts, balances and transactions

A scryp account has an id and a balance.

The id is the 32-byte public key of the account holder.

The balance is a 4-byte integer which can have a value from 0 to 232-1; the combined balance of all accounts is 232-1 or 4,294,967,295 ~ 4.3 billion. The account unit of balance is the scryp.

The goal of scryp servers is to keep an accurate and current record of all account balances. Together, an account id and balance form a 36-byte data set:

idbalance
32 bytes4 bytes

A transaction consists of a 140-byte data set with the following fields, in order:

time stampamountpayee idpayer idpayer signature
8 bytes4 bytes32 bytes32 bytes64 bytes

The time stamp is the number of milliseconds elapsed since 00:00:00 01-01-1970 UTC, not including leap seconds; it has the same value for everyone on Earth. See the current Unix time stamp in decimal form here.

The amount is the payment amount.

The payee id is the destination account id.

The payer id is the origination account id.

The payer signature is the payer's signature of the preceding 76 bytes using the payer's public/secret key pair.

These are the basic data structures of scryp. It's doubtful that a cryptocurrency can be any simpler.

Here's a node.js program that packs a transaction, signs it, verifies it, and unpacks one field:

ed = require('ed25519-supercop')

function padZero (str, len) { // pad beginning of string with zeros if length is less than len
  if (len <= str.length) return str
  return '0'.repeat(len - str.length) + str
}

timestamp = padZero(Date.now().toString(16), 16) // 16 hex-digit string
amount = 100 // decimal
amt = padZero(parseInt(amount, 10).toString(16), 8) // hex-digit string '00000064'
payeeId = '0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef' // 32-byte payee's public key
payerId = '709efff9bb2e3af305070b275fe9defa1f0239910a352cfedc76ad96263a0916' // 32-byte payer's public key
payerSecretKey = '687ad3ca223beacc9d59ffb4451acd0e8b4fa67583b672997433d5a16671ba78cb51a103c437f8cf1dae192a42b361413a0e317e535147484ade8b65ed6f0596' // 64-byte payer's secret key

rawTx = Buffer.from(timestamp + amt + payeeId + payerId, 'hex')
signedTx = Buffer.concat([rawTx, ed.sign(rawTx, payerId, payerSecretKey)])

console.log(signedTx.length) // 140 bytes
console.log(signedTx)
console.log(signedTx.toString('hex'))

console.log(ed.verify(signedTx.slice(76), signedTx.slice(0, 76), signedTx.slice(44, 76))) // true
console.log(parseInt(signedTx.slice(8, 12).toString('hex'), 16)) // amount = 100


The signed transaction in hex form is:

0000015c989bfe98000000640123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef709efff9bb2e3af305070b275fe9defa1f0239910a352cfedc76ad96263a0916c7d000457c0f447b1059a142d681e65a71dc96495c289cef3068d70dfc4c03443d823219dbf8d39471c4337cf664ca6f3562871c124f4d6877bfd794de504501


< part 2 | part 4 >