mirror of https://github.com/status-im/nim-eth.git
Support for compressed public key format
This commit is contained in:
parent
bf96e13d41
commit
10e35d3def
|
@ -12,6 +12,7 @@ import secp256k1, nimcrypto/sysrand, nimcrypto/utils
|
|||
|
||||
const
|
||||
KeyLength* = 256 div 8
|
||||
CompressedPubKeyLength* = 33
|
||||
RawSignatureSize* = KeyLength * 2 + 1
|
||||
RawPublicKeySize* = KeyLength * 2
|
||||
InvalidPrivateKey = "Invalid private key!"
|
||||
|
@ -154,16 +155,24 @@ proc recoverPublicKey*(data: openarray[byte],
|
|||
## Unserialize public key from `data`.
|
||||
let ctx = getSecpContext()
|
||||
let length = len(data)
|
||||
if length < RawPublicKeySize:
|
||||
if length >= RawPublicKeySize:
|
||||
var rawkey: array[RawPublicKeySize + 1, byte]
|
||||
rawkey[0] = 0x04'u8 # mark key with UNCOMPRESSED flag
|
||||
copyMem(addr rawkey[1], unsafeAddr data[0], RawPublicKeySize)
|
||||
if secp256k1_ec_pubkey_parse(ctx, addr pubkey,
|
||||
cast[ptr cuchar](addr rawkey),
|
||||
RawPublicKeySize + 1) != 1:
|
||||
return(EthKeysStatus.Error)
|
||||
elif length == CompressedPubKeyLength:
|
||||
# Compressed format
|
||||
if secp256k1_ec_pubkey_parse(ctx, addr pubkey,
|
||||
cast[ptr cuchar](unsafeAddr data),
|
||||
length) != 1:
|
||||
return(EthKeysStatus.Error)
|
||||
else:
|
||||
setErrorMsg(InvalidPublicKey)
|
||||
return(EthKeysStatus.Error)
|
||||
var rawkey: array[RawPublicKeySize + 1, byte]
|
||||
rawkey[0] = 0x04'u8 # mark key with UNCOMPRESSED flag
|
||||
copyMem(addr rawkey[1], unsafeAddr data[0], RawPublicKeySize)
|
||||
if secp256k1_ec_pubkey_parse(ctx, addr pubkey,
|
||||
cast[ptr cuchar](addr rawkey),
|
||||
RawPublicKeySize + 1) != 1:
|
||||
return(EthKeysStatus.Error)
|
||||
|
||||
result = EthKeysStatus.Success
|
||||
|
||||
proc recoverSignature*(data: openarray[byte],
|
||||
|
@ -184,8 +193,6 @@ proc recoverSignature*(data: openarray[byte],
|
|||
proc initPublicKey*(hexstr: string): PublicKey =
|
||||
## Create new public key from hexadecimal string representation.
|
||||
var o = fromHex(stripSpaces(hexstr))
|
||||
if len(o) < RawPublicKeySize:
|
||||
raise newException(EthKeysException, InvalidPublicKey)
|
||||
if recoverPublicKey(o, result) != EthKeysStatus.Success:
|
||||
raise newException(EthKeysException, InvalidPublicKey)
|
||||
|
||||
|
@ -217,32 +224,36 @@ proc ecdhAgree*(seckey: PrivateKey, pubkey: PublicKey,
|
|||
copyMem(addr secret, addr res[1], KeyLength)
|
||||
return(EthKeysStatus.Success)
|
||||
|
||||
proc getRaw*(pubkey: PublicKey): array[RawPublicKeySize, byte] {.noinit.} =
|
||||
## Converts public key `pubkey` to serialized form.
|
||||
var key: array[RawPublicKeySize + 1, byte]
|
||||
var length = csize(sizeof(key))
|
||||
let ctx = getSecpContext()
|
||||
if secp256k1_ec_pubkey_serialize(ctx, cast[ptr cuchar](addr key),
|
||||
addr length, unsafeAddr pubkey,
|
||||
SECP256K1_EC_UNCOMPRESSED) != 1:
|
||||
raiseSecp256k1Error()
|
||||
doAssert(length == RawPublicKeySize + 1)
|
||||
doAssert(key[0] == 0x04'u8)
|
||||
copyMem(addr result[0], addr key[1], RawPublicKeySize)
|
||||
|
||||
proc toRaw*(pubkey: PublicKey, data: var openarray[byte]) =
|
||||
proc toRaw*(pubkey: PublicKey, data: var openarray[byte], compressed = false) =
|
||||
## Converts public key `pubkey` to serialized form and store it in `data`.
|
||||
var key: array[RawPublicKeySize + 1, byte]
|
||||
doAssert(len(data) >= RawPublicKeySize)
|
||||
var length = csize(sizeof(key))
|
||||
let ctx = getSecpContext()
|
||||
if secp256k1_ec_pubkey_serialize(ctx, cast[ptr cuchar](addr key),
|
||||
addr length, unsafeAddr pubkey,
|
||||
SECP256K1_EC_UNCOMPRESSED) != 1:
|
||||
raiseSecp256k1Error()
|
||||
doAssert(length == RawPublicKeySize + 1)
|
||||
doAssert(key[0] == 0x04'u8)
|
||||
copyMem(addr data[0], addr key[1], RawPublicKeySize)
|
||||
if compressed:
|
||||
var length = len(data)
|
||||
doAssert(length >= CompressedPubKeyLength)
|
||||
let ctx = getSecpContext()
|
||||
if secp256k1_ec_pubkey_serialize(ctx, cast[ptr cuchar](addr data[0]),
|
||||
addr length, unsafeAddr pubkey,
|
||||
SECP256K1_EC_COMPRESSED) != 1:
|
||||
raiseSecp256k1Error()
|
||||
else:
|
||||
var key: array[RawPublicKeySize + 1, byte]
|
||||
doAssert(len(data) >= RawPublicKeySize)
|
||||
var length = csize(sizeof(key))
|
||||
let ctx = getSecpContext()
|
||||
if secp256k1_ec_pubkey_serialize(ctx, cast[ptr cuchar](addr key),
|
||||
addr length, unsafeAddr pubkey,
|
||||
SECP256K1_EC_UNCOMPRESSED) != 1:
|
||||
raiseSecp256k1Error()
|
||||
doAssert(length == RawPublicKeySize + 1)
|
||||
doAssert(key[0] == 0x04'u8)
|
||||
copyMem(addr data[0], addr key[1], RawPublicKeySize)
|
||||
|
||||
proc getRaw*(pubkey: PublicKey): array[RawPublicKeySize, byte] {.noinit, inline.} =
|
||||
## Converts public key `pubkey` to serialized form.
|
||||
pubkey.toRaw(result)
|
||||
|
||||
proc getRawCompressed*(pubkey: PublicKey): array[CompressedPubKeyLength, byte] {.noinit, inline.} =
|
||||
## Converts public key `pubkey` to serialized form.
|
||||
pubkey.toRaw(result, true)
|
||||
|
||||
proc getRaw*(s: Signature): array[RawSignatureSize, byte] {.noinit.} =
|
||||
## Converts signature `s` to serialized form.
|
||||
|
|
|
@ -266,3 +266,12 @@ suite "ECC/ECDSA/ECDHE tests suite":
|
|||
pubkey1.isZeroKey() == true
|
||||
seckey2.isZeroKey() == false
|
||||
pubkey2.isZeroKey() == false
|
||||
|
||||
test "Compressed public keys":
|
||||
let pubkeyCompressed = "03CA634CAE0D49ACB401D8A4C6B6FE8C55B70D115BF400769CC1400F3258CD3138"
|
||||
let s = initPublicKey(pubkeyCompressed)
|
||||
check:
|
||||
s.getRaw.toHex == """CA634CAE0D49ACB401D8A4C6B6FE8C55B70D115BF400769CC1400F3258
|
||||
CD31387574077F301B421BC84DF7266C44E9E6D569FC56BE00812904767BF5CCD1FC7F""".stripSpaces
|
||||
|
||||
s.getRawCompressed.toHex == pubkeyCompressed
|
||||
|
|
Loading…
Reference in New Issue