package
1.3.9
Repository: https://github.com/ndau/ndaumath.git
Documentation: pkg.go.dev

# Packages

No description provided by the author

# README

ndau key format

The keys for ndau are designed to be:

  • able to grow as keys and cryptography evolve
  • distinct from keys used for other cryptocurrencies
  • private and public keys are easily identifiable
  • human-readable
  • encoded in a way that they could be read aloud and manually typed without confusion
  • able to detect minor typos

Essentially, keys are converted to a binary form, and then converted to a base32 representation where case doesn't matter, the characters i, o, 1 and 0 are omitted, and includes a checksum.

Algorithm

Build a binary key

The instructions below are for non-extended keys ONLY. The "extra" bytes that apply to HD key trees are ignored in these instructions; the system supports doing this for extended keys but the explanation of how they are serialized is more complex.

  • Determine the key type (0=null key, 1=ed25519, 2=secp256k1)
  • Determine the key length:
    • ed25519 public keys are 32 bytes
    • ed25519 private keys are 64 bytes
    • secp256k1 public keys are 33 bytes
    • secp256k1 private keys are 32 bytes
  • Build the 5-byte prefix, which consists of 0x92, the key type, 0xc4, keylen+1, keylen:
    • for ed25519 public keys it is 9201c42120
    • for ed25519 private keys it is 9201c44140
    • for secp256k1 public keys it is 9202c42221
    • for secp256k1 private keys it is 9202c42120
  • Build the "packed" byte array, which concatenates:
    • The prefix
    • The bytes of the key
  • Calculate the checksum of this byte array. This is done by:
    • Calculating the number of bytes in the checksum, which is the number of bytes needed to pad the length of the array to a multiple of 5 -- but that number must be a minimum of 3. (So the checksum length will be between 3 and 7 bytes). For the keys below, that will be:
      • ed25519 public keys need 3 bytes
      • ed25519 private keys need 6 bytes
      • secp256k1 public keys need 7 bytes
      • secp256k1 private keys need 3 bytes
    • calculate the checksum as the trailing n bytes of the sha224 checksum of the input bytes
    • append the checksum to the end of the input bytes, making the total length a multiple of 5
    • convert the input byte stream to base32 using the alphabet abcdefghijkmnpqrstuvwxyz23456789
    • add "npub" for public keys and "npvt" for private keys to the front of the string

Sample checksum calculation in Go:

func cksumN(input []byte, n byte) []byte {
	sum := sha256.Sum224(input)
	return sum[sha256.Size224-int(n):]
}

Examples

Ed25519Public

  • raw key: 9e3e08c194fae465c70e0ac0487f63b00dd969c13e45417731d1ab12768f8636 (len 32)
  • packed: 9201c421209e3e08c194fae465c70e0ac0487f63b00dd969c13e45417731d1ab12768f8636 (len 37)
  • result: npuba8jadtbbecrd6cgbuv7qi3qhb2fnaud9nq2a5ymj2e9eksmzghi4yevyt8ddnuxhgw33b8ed

Ed25519Private

  • raw key: db531a15b6444c71b790aae7ae9dd6b3f87561319399af6e490ae1078cda9e03cd5c569c7160d694a9a2607944a267b7cd5fed312d3ef854cc46b5cf92857f2e (len 64)
  • packed: 9201c44140db531a15b6444c71b790aae7ae9dd6b3f87561319399af6e490ae1078cda9e03cd5c569c7160d694a9a2607944a267b7cd5fed312d3ef854cc46b5cf92857f2e (len 69)
  • result: npvtayjadtcbidpxggsxy3ce26pzucxqrmw74439s7mbggj3vm5qjefqcb6n5krahvk6k4qhc2gyuuw4e2d3iutgrp8pm9yvcmj89bkn2txx38jik93qvwy9fxad

Secp256k1Public

  • raw key: 02d235e59fc697cb3a2a416c60f1c4af1edf68fdd21001c97091a5f45db4267f1d (len 33)
  • packed: 9202c4222102d235e59fc697cb3a2a416c60f1c4af1edf68fdd21001c97091a5f45db4267f1d (len 38)
  • result: npuba4jaftbceebpeprfv9djru34fjay22ht2uzt7z5i9zjbaaqjqci4m7c7ysvh8hpwj3zwvgpn

Secp256k1Private

  • raw key: 72422691b240a4fd9b7ee6f31be97042ed38d2b8e126fe2d865958a9e2533e4e (len 32)
  • packed: 9202c4212072422691b240a4fd9b7ee6f31be97042ed38d2b8e126fe2d865958a9e2533e4e (len 37)
  • result: npvta8jaftbbeb3eejwtyjakj9n5r5vrgg9jqbbq4qguzdsup9tps3nxtkrckn9e643gumuxyt7z

ndau signature format

ndau signatures follow a similar pattern.

Signing transactions

  • Get the raw bytes of the private key
  • Generate the SignableBytes of the transaction (see below)
  • Sign the SignableBytes (do not hash it first) using the private key's standard signature algorithm
  • Calculate the checksum of the signature using the algorithm above
  • Generate the base32 representation using the same alphabet above

Signable Bytes

A transaction must be signed, but the signature itself must not be part of the signed result. To calculate the collection of Signable Bytes for any transaction:

  • Sort the JSON field names alphabetically
  • Build a byte array concatenating all the bytes of each of the field types:
    • If the field name matches the regular expression "[sS]ignature[s]?", it should be skipped
    • String -- use the bytes of the string
    • Positive integer and quantity of ndau -- store the 64-bit (8 bytes) representation of the quantity, highest-byte first. The value 258 would be stored as 00 00 00 00 00 00 01 02. Note that JavaScript can't accurately represent more than 53 bits so care must be taken when using JS.
    • Boolean -- true is 0x01, false is 0x00
    • Duration -- store the bytes of the text representation of the duration (1y5m17dt4h37m)
    • Nested objects -- treat recursively: sort the subkeys and record the concatenated values
  • The resulting byte array is the SignableBytes of the transaction

Verifying a transaction:

  • Get the raw bytes of the public key, decoding as necessary
  • Generate the SignableBytes of the transaction
  • Get the raw bytes of the signature
  • Verify the SignableBytes using the public key's standard verify algorithm