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
|
const
|
||||||
KeyLength* = 256 div 8
|
KeyLength* = 256 div 8
|
||||||
|
CompressedPubKeyLength* = 33
|
||||||
RawSignatureSize* = KeyLength * 2 + 1
|
RawSignatureSize* = KeyLength * 2 + 1
|
||||||
RawPublicKeySize* = KeyLength * 2
|
RawPublicKeySize* = KeyLength * 2
|
||||||
InvalidPrivateKey = "Invalid private key!"
|
InvalidPrivateKey = "Invalid private key!"
|
||||||
|
@ -154,16 +155,24 @@ proc recoverPublicKey*(data: openarray[byte],
|
||||||
## Unserialize public key from `data`.
|
## Unserialize public key from `data`.
|
||||||
let ctx = getSecpContext()
|
let ctx = getSecpContext()
|
||||||
let length = len(data)
|
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)
|
setErrorMsg(InvalidPublicKey)
|
||||||
return(EthKeysStatus.Error)
|
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
|
result = EthKeysStatus.Success
|
||||||
|
|
||||||
proc recoverSignature*(data: openarray[byte],
|
proc recoverSignature*(data: openarray[byte],
|
||||||
|
@ -184,8 +193,6 @@ proc recoverSignature*(data: openarray[byte],
|
||||||
proc initPublicKey*(hexstr: string): PublicKey =
|
proc initPublicKey*(hexstr: string): PublicKey =
|
||||||
## Create new public key from hexadecimal string representation.
|
## Create new public key from hexadecimal string representation.
|
||||||
var o = fromHex(stripSpaces(hexstr))
|
var o = fromHex(stripSpaces(hexstr))
|
||||||
if len(o) < RawPublicKeySize:
|
|
||||||
raise newException(EthKeysException, InvalidPublicKey)
|
|
||||||
if recoverPublicKey(o, result) != EthKeysStatus.Success:
|
if recoverPublicKey(o, result) != EthKeysStatus.Success:
|
||||||
raise newException(EthKeysException, InvalidPublicKey)
|
raise newException(EthKeysException, InvalidPublicKey)
|
||||||
|
|
||||||
|
@ -217,32 +224,36 @@ proc ecdhAgree*(seckey: PrivateKey, pubkey: PublicKey,
|
||||||
copyMem(addr secret, addr res[1], KeyLength)
|
copyMem(addr secret, addr res[1], KeyLength)
|
||||||
return(EthKeysStatus.Success)
|
return(EthKeysStatus.Success)
|
||||||
|
|
||||||
proc getRaw*(pubkey: PublicKey): array[RawPublicKeySize, byte] {.noinit.} =
|
proc toRaw*(pubkey: PublicKey, data: var openarray[byte], compressed = false) =
|
||||||
## 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]) =
|
|
||||||
## Converts public key `pubkey` to serialized form and store it in `data`.
|
## Converts public key `pubkey` to serialized form and store it in `data`.
|
||||||
var key: array[RawPublicKeySize + 1, byte]
|
if compressed:
|
||||||
doAssert(len(data) >= RawPublicKeySize)
|
var length = len(data)
|
||||||
var length = csize(sizeof(key))
|
doAssert(length >= CompressedPubKeyLength)
|
||||||
let ctx = getSecpContext()
|
let ctx = getSecpContext()
|
||||||
if secp256k1_ec_pubkey_serialize(ctx, cast[ptr cuchar](addr key),
|
if secp256k1_ec_pubkey_serialize(ctx, cast[ptr cuchar](addr data[0]),
|
||||||
addr length, unsafeAddr pubkey,
|
addr length, unsafeAddr pubkey,
|
||||||
SECP256K1_EC_UNCOMPRESSED) != 1:
|
SECP256K1_EC_COMPRESSED) != 1:
|
||||||
raiseSecp256k1Error()
|
raiseSecp256k1Error()
|
||||||
doAssert(length == RawPublicKeySize + 1)
|
else:
|
||||||
doAssert(key[0] == 0x04'u8)
|
var key: array[RawPublicKeySize + 1, byte]
|
||||||
copyMem(addr data[0], addr key[1], RawPublicKeySize)
|
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.} =
|
proc getRaw*(s: Signature): array[RawSignatureSize, byte] {.noinit.} =
|
||||||
## Converts signature `s` to serialized form.
|
## Converts signature `s` to serialized form.
|
||||||
|
|
|
@ -266,3 +266,12 @@ suite "ECC/ECDSA/ECDHE tests suite":
|
||||||
pubkey1.isZeroKey() == true
|
pubkey1.isZeroKey() == true
|
||||||
seckey2.isZeroKey() == false
|
seckey2.isZeroKey() == false
|
||||||
pubkey2.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