mirror of https://github.com/status-im/nim-eth.git
Addded non-recoverable signature type and routines
This commit is contained in:
parent
658e5a3cc8
commit
091239a710
|
@ -13,7 +13,8 @@ import secp256k1, nimcrypto/sysrand, nimcrypto/utils
|
||||||
const
|
const
|
||||||
KeyLength* = 256 div 8
|
KeyLength* = 256 div 8
|
||||||
CompressedPubKeyLength* = 33
|
CompressedPubKeyLength* = 33
|
||||||
RawSignatureSize* = KeyLength * 2 + 1
|
RawSignatureNRSize* = KeyLength * 2 # Non-recoverable signature
|
||||||
|
RawSignatureSize* = RawSignatureNRSize + 1 # Recoverable
|
||||||
RawPublicKeySize* = KeyLength * 2
|
RawPublicKeySize* = KeyLength * 2
|
||||||
InvalidPrivateKey = "Invalid private key!"
|
InvalidPrivateKey = "Invalid private key!"
|
||||||
InvalidPublicKey = "Invalid public key!"
|
InvalidPublicKey = "Invalid public key!"
|
||||||
|
@ -33,6 +34,11 @@ type
|
||||||
## Representation of ECDH shared secret
|
## Representation of ECDH shared secret
|
||||||
data*: array[KeyLength, byte]
|
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
|
KeyPair* = object
|
||||||
## Representation of private/public keys pair
|
## Representation of private/public keys pair
|
||||||
seckey*: PrivateKey
|
seckey*: PrivateKey
|
||||||
|
@ -41,6 +47,9 @@ type
|
||||||
Signature* = secp256k1_ecdsa_recoverable_signature
|
Signature* = secp256k1_ecdsa_recoverable_signature
|
||||||
## Representation of signature
|
## Representation of signature
|
||||||
|
|
||||||
|
SignatureNR* = secp256k1_ecdsa_signature
|
||||||
|
## Representation of non-recoverable signature
|
||||||
|
|
||||||
Secp256k1Exception* = object of Exception
|
Secp256k1Exception* = object of Exception
|
||||||
## Exceptions generated by `libsecp256k1`
|
## Exceptions generated by `libsecp256k1`
|
||||||
|
|
||||||
|
@ -175,12 +184,23 @@ proc recoverPublicKey*(data: openarray[byte],
|
||||||
|
|
||||||
result = EthKeysStatus.Success
|
result = EthKeysStatus.Success
|
||||||
|
|
||||||
proc recoverSignature*(data: openarray[byte],
|
proc parseCompact*(signature: var SignatureNR, data: openarray[byte]): EthKeysStatus =
|
||||||
signature: var Signature): 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`.
|
## Unserialize signature from `data`.
|
||||||
let ctx = getSecpContext()
|
let ctx = getSecpContext()
|
||||||
let length = len(data)
|
let length = len(data)
|
||||||
if length < RawSignatureSize:
|
if length != RawSignatureSize:
|
||||||
setErrorMsg(InvalidSignature)
|
setErrorMsg(InvalidSignature)
|
||||||
return(EthKeysStatus.Error)
|
return(EthKeysStatus.Error)
|
||||||
var recid = cint(data[KeyLength * 2])
|
var recid = cint(data[KeyLength * 2])
|
||||||
|
@ -190,6 +210,14 @@ proc recoverSignature*(data: openarray[byte],
|
||||||
return(EthKeysStatus.Error)
|
return(EthKeysStatus.Error)
|
||||||
result = EthKeysStatus.Success
|
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 =
|
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))
|
||||||
|
@ -212,6 +240,16 @@ proc initSignature*(data: openarray[byte]): Signature =
|
||||||
if recoverSignature(data, result) != EthKeysStatus.Success:
|
if recoverSignature(data, result) != EthKeysStatus.Success:
|
||||||
raise newException(EthKeysException, libsecp256k1ErrorMsg())
|
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,
|
proc ecdhAgree*(seckey: PrivateKey, pubkey: PublicKey,
|
||||||
secret: var SharedSecret): EthKeysStatus =
|
secret: var SharedSecret): EthKeysStatus =
|
||||||
## Calculate ECDH shared secret.
|
## Calculate ECDH shared secret.
|
||||||
|
@ -255,15 +293,6 @@ proc getRawCompressed*(pubkey: PublicKey): array[CompressedPubKeyLength, byte] {
|
||||||
## Converts public key `pubkey` to serialized form.
|
## Converts public key `pubkey` to serialized form.
|
||||||
pubkey.toRaw(result, true)
|
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]) =
|
proc toRaw*(s: Signature, data: var openarray[byte]) =
|
||||||
## Converts signature `s` to serialized form and store it in `data`.
|
## Converts signature `s` to serialized form and store it in `data`.
|
||||||
let ctx = getSecpContext()
|
let ctx = getSecpContext()
|
||||||
|
@ -274,6 +303,22 @@ proc toRaw*(s: Signature, data: var openarray[byte]) =
|
||||||
raiseSecp256k1Error()
|
raiseSecp256k1Error()
|
||||||
data[64] = uint8(recid)
|
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],
|
proc recoverSignatureKey*(data: openarray[byte],
|
||||||
msg: openarray[byte],
|
msg: openarray[byte],
|
||||||
pubkey: var PublicKey): EthKeysStatus =
|
pubkey: var PublicKey): EthKeysStatus =
|
||||||
|
@ -330,3 +375,34 @@ proc signRawMessage*(data: openarray[byte], seckey: PrivateKey,
|
||||||
return(EthKeysStatus.Error)
|
return(EthKeysStatus.Error)
|
||||||
return(EthKeysStatus.Success)
|
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)
|
||||||
|
|
Loading…
Reference in New Issue