Addded non-recoverable signature type and routines

This commit is contained in:
Yuriy Glukhov 2019-12-10 20:32:47 +02:00 committed by zah
parent 658e5a3cc8
commit 091239a710
1 changed files with 89 additions and 13 deletions

View File

@ -13,7 +13,8 @@ import secp256k1, nimcrypto/sysrand, nimcrypto/utils
const
KeyLength* = 256 div 8
CompressedPubKeyLength* = 33
RawSignatureSize* = KeyLength * 2 + 1
RawSignatureNRSize* = KeyLength * 2 # Non-recoverable signature
RawSignatureSize* = RawSignatureNRSize + 1 # Recoverable
RawPublicKeySize* = KeyLength * 2
InvalidPrivateKey = "Invalid private key!"
InvalidPublicKey = "Invalid public key!"
@ -33,6 +34,11 @@ type
## Representation of ECDH shared secret
data*: array[KeyLength, byte]
SharedSecretFull* = object
## Representation of ECDH shared secret, with leading `y` byte
# (`y` is 0x02 when pubkey.y is even or 0x03 when odd)
data*: array[1 + KeyLength, byte]
KeyPair* = object
## Representation of private/public keys pair
seckey*: PrivateKey
@ -41,6 +47,9 @@ type
Signature* = secp256k1_ecdsa_recoverable_signature
## Representation of signature
SignatureNR* = secp256k1_ecdsa_signature
## Representation of non-recoverable signature
Secp256k1Exception* = object of Exception
## Exceptions generated by `libsecp256k1`
@ -175,12 +184,23 @@ proc recoverPublicKey*(data: openarray[byte],
result = EthKeysStatus.Success
proc recoverSignature*(data: openarray[byte],
signature: var Signature): EthKeysStatus =
proc parseCompact*(signature: var SignatureNR, data: openarray[byte]): EthKeysStatus =
let ctx = getSecpContext()
let length = len(data)
if length == RawSignatureNRSize:
if secp256k1_ecdsa_signature_parse_compact(ctx, addr signature,
cast[ptr cuchar](unsafeAddr data[0])) != 1:
return(EthKeysStatus.Error)
else:
setErrorMsg(InvalidSignature)
return(EthKeysStatus.Error)
result = EthKeysStatus.Success
proc parseCompact*(signature: var Signature, data: openarray[byte]): EthKeysStatus =
## Unserialize signature from `data`.
let ctx = getSecpContext()
let length = len(data)
if length < RawSignatureSize:
if length != RawSignatureSize:
setErrorMsg(InvalidSignature)
return(EthKeysStatus.Error)
var recid = cint(data[KeyLength * 2])
@ -190,6 +210,14 @@ proc recoverSignature*(data: openarray[byte],
return(EthKeysStatus.Error)
result = EthKeysStatus.Success
proc recoverSignature*(data: openarray[byte],
signature: var Signature): EthKeysStatus {.deprecated.} =
## Deprecated, use `parseCompact` instead
if data.len < RawSignatureSize:
setErrorMsg(InvalidSignature)
return(EthKeysStatus.Error)
signature.parseCompact(data.toOpenArray(0, RawSignatureSize - 1))
proc initPublicKey*(hexstr: string): PublicKey =
## Create new public key from hexadecimal string representation.
var o = fromHex(stripSpaces(hexstr))
@ -212,6 +240,16 @@ proc initSignature*(data: openarray[byte]): Signature =
if recoverSignature(data, result) != EthKeysStatus.Success:
raise newException(EthKeysException, libsecp256k1ErrorMsg())
proc ecdhAgree*(seckey: PrivateKey, pubkey: PublicKey,
secret: var SharedSecretFull): EthKeysStatus =
## Calculate ECDH shared secret.
let ctx = getSecpContext()
if secp256k1_ecdh_raw(ctx, cast[ptr cuchar](addr secret.data),
unsafeAddr pubkey,
cast[ptr cuchar](unsafeAddr seckey)) != 1:
return(EthKeysStatus.Error)
return(EthKeysStatus.Success)
proc ecdhAgree*(seckey: PrivateKey, pubkey: PublicKey,
secret: var SharedSecret): EthKeysStatus =
## Calculate ECDH shared secret.
@ -255,15 +293,6 @@ proc getRawCompressed*(pubkey: PublicKey): array[CompressedPubKeyLength, byte] {
## 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.
let ctx = getSecpContext()
var recid = cint(0)
if secp256k1_ecdsa_recoverable_signature_serialize_compact(
ctx, cast[ptr cuchar](unsafeAddr result), addr recid, unsafeAddr s) != 1:
raiseSecp256k1Error()
result[64] = uint8(recid)
proc toRaw*(s: Signature, data: var openarray[byte]) =
## Converts signature `s` to serialized form and store it in `data`.
let ctx = getSecpContext()
@ -274,6 +303,22 @@ proc toRaw*(s: Signature, data: var openarray[byte]) =
raiseSecp256k1Error()
data[64] = uint8(recid)
proc getRaw*(s: Signature): array[RawSignatureSize, byte] {.noinit.} =
## Converts signature `s` to serialized form.
s.toRaw(result)
proc toRaw*(s: SignatureNR, data: var openarray[byte]) =
## Converts signature `s` to serialized form and store it in `data`.
doAssert(len(data) == RawSignatureNRSize)
let ctx = getSecpContext()
if secp256k1_ecdsa_signature_serialize_compact(ctx, cast[ptr cuchar](addr data[0]),
unsafeAddr s) != 1:
raiseSecp256k1Error()
proc getRaw*(s: SignatureNR): array[RawSignatureNRSize, byte] {.noinit.} =
## Converts signature `s` to serialized form.
s.toRaw(result)
proc recoverSignatureKey*(data: openarray[byte],
msg: openarray[byte],
pubkey: var PublicKey): EthKeysStatus =
@ -330,3 +375,34 @@ proc signRawMessage*(data: openarray[byte], seckey: PrivateKey,
return(EthKeysStatus.Error)
return(EthKeysStatus.Success)
proc signRawMessage*(data: openarray[byte], seckey: PrivateKey,
signature: var SignatureNR): EthKeysStatus =
## Sign message `data` of `KeyLength` size using private key `seckey` and
## store result into `signature`.
let ctx = getSecpContext()
let length = len(data)
if length != KeyLength:
setErrorMsg(MessageSizeError)
return(EthKeysStatus.Error)
if secp256k1_ecdsa_sign(ctx, addr signature,
cast[ptr cuchar](unsafeAddr data[0]),
cast[ptr cuchar](unsafeAddr seckey),
nil, nil) != 1:
return(EthKeysStatus.Error)
return(EthKeysStatus.Success)
proc verifySignatureRaw*(signature: SignatureNR, message: openarray[byte],
publicKey: PublicKey): EthKeysStatus =
## Verify `signature` using original `message` (32 bytes) and `publicKey`.
let ctx = getSecpContext()
if len(message) != KeyLength:
setErrorMsg(MessageSizeError)
return(EthKeysStatus.Error)
if secp256k1_ecdsa_verify(ctx, unsafeAddr signature,
cast[ptr cuchar](unsafeAddr message[0]),
unsafeAddr publicKey) != 1:
setErrorMsg(VerificationFailed)
return(EthKeysStatus.Error)
return(EthKeysStatus.Success)