PublicKey serialization and stringification (#8)

This commit is contained in:
Yuriy Glukhov 2018-03-21 11:57:36 +02:00 committed by Mamy Ratsimbazafy
parent 74bdca4f1c
commit ef185ff1ee
3 changed files with 42 additions and 6 deletions

View File

@ -48,8 +48,8 @@ proc private_key_to_public_key*(key: PrivateKey): PublicKey {.noInit.}=
if not success:
raise newException(ValueError, "Private key is invalid")
proc serialize*(key: PublicKey): string =
## Exports a publicKey to a hex string
proc serialize*(key: PublicKey, output: var openarray[byte], addPrefix = false) =
## Exports a publicKey to `output` buffer so that it can be
var
tmp{.noInit.}: Serialized_PubKey
tmp_len: csize = 65
@ -64,14 +64,43 @@ proc serialize*(key: PublicKey): string =
)
assert tmp_len == 65 # header 0x04 (uncompressed) + 128 hex char
if addPrefix:
assert(output.len >= 65)
copyMem(addr output[0], addr tmp[0], 65)
else:
assert(output.len >= 64)
copyMem(addr output[0], addr tmp[1], 64) # Skip the 0x04 prefix
result = tmp.toHex
proc toString*(key: PublicKey): string =
var data: array[64, byte]
key.serialize(data)
result = data.toHex
proc parsePublicKey*(data: openarray[byte]): PublicKey =
proc toStringWithPrefix*(key: PublicKey): string =
var data: array[65, byte]
key.serialize(data, true)
result = data.toHex
proc serialize*(key: PublicKey): string {.deprecated.} = key.toStringWithPrefix()
proc parsePublicKeyWithPrefix(data: openarray[byte], result: var PublicKey) =
## Parse a variable-length public key into the PublicKey object
if secp256k1_ec_pubkey_parse(ctx, result.asPtrPubKey, cast[ptr cuchar](unsafeAddr data[0]), data.len.csize) != 1:
raise newException(Exception, "Could not parse public key")
proc parsePublicKey*(data: openarray[byte]): PublicKey =
## Parse a variable-length public key into the PublicKey object
case data.len
of 65:
parsePublicKeyWithPrefix(data, result)
of 64:
var tmpData: Serialized_PubKey
copyMem(addr tmpData[1], unsafeAddr data[0], 64)
tmpData[0] = 0x04
parsePublicKeyWithPrefix(tmpData, result)
else: # TODO: Support other lengths
raise newException(Exception, "Wrong public key length")
proc ecdsa_sign*(key: PrivateKey, msg_hash: Hash[256]): Signature {.noInit.}=
## Sign a message with a recoverable signature
## Input:
@ -103,3 +132,5 @@ proc ecdsa_recover*(msg_hash: Hash[256], sig: Signature): PublicKey =
if not success:
raise newException(ValueError, "Failed to recover public key. Is the signature correct?")
proc `$`*(key: PublicKey): string {.inline.} = key.toString()

View File

@ -23,6 +23,8 @@ when defined(backend_native):
else:
import ./backend_libsecp256k1/libsecp256k1
export libsecp256k1.serialize
export libsecp256k1.`$`
export libsecp256k1.parsePublicKey
# ################################
# Initialization
@ -63,3 +65,6 @@ proc sign_msg*(key: PrivateKey, message: string): Signature {.inline.} =
proc sign_msg*(key: PrivateKey, message_hash: Hash[256]): Signature {.inline.} =
ecdsa_sign(key, message_hash)
proc `$`*(key: PrivateKey): string {.inline.} =
key.raw_key.toHex()

View File

@ -17,6 +17,6 @@ suite "Testing private -> public key conversion":
for person in [alice, bob, eve]:
let privkey = initPrivateKey(person.privkey)
let computed_pubkey = privkey.public_key.serialize
let computed_pubkey = $privkey.public_key
check: computed_pubkey == "04" & person.pubkey # Serialization prefixes uncompressed public keys with 04
check: computed_pubkey == person.pubkey