Remove ecc.nim.
Remove testecc.nim. Switch auth/ecies to use eth_keys instead of ecc.nim. Fix tests according to new API.
This commit is contained in:
parent
f8ba94b39e
commit
d7bd43c334
|
@ -18,7 +18,6 @@ requires "nim > 0.18.0",
|
||||||
proc runTest(name: string, lang = "c") = exec "nim " & lang & " -r tests/" & name
|
proc runTest(name: string, lang = "c") = exec "nim " & lang & " -r tests/" & name
|
||||||
|
|
||||||
task test, "Runs the test suite":
|
task test, "Runs the test suite":
|
||||||
runTest "testecc"
|
|
||||||
runTest "testecies"
|
runTest "testecies"
|
||||||
runTest "testauth"
|
runTest "testauth"
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
## This module implements Ethereum authentication
|
## This module implements Ethereum authentication
|
||||||
|
|
||||||
import endians
|
import endians
|
||||||
import ecc, ecies, rlp
|
import eth_keys, ecies, rlp
|
||||||
import nimcrypto/sysrand, nimcrypto/hash, nimcrypto/utils, nimcrypto/hmac
|
import nimcrypto/sysrand, nimcrypto/hash, nimcrypto/utils, nimcrypto/hmac
|
||||||
import nimcrypto/rijndael, nimcrypto/keccak, nimcrypto/sha2
|
import nimcrypto/rijndael, nimcrypto/keccak, nimcrypto/sha2
|
||||||
|
|
||||||
|
@ -30,15 +30,17 @@ const
|
||||||
AckMessageMaxEIP8* = AckMessageEIP8Length + 255
|
AckMessageMaxEIP8* = AckMessageEIP8Length + 255
|
||||||
|
|
||||||
type
|
type
|
||||||
|
Nonce* = array[KeyLength, byte]
|
||||||
|
|
||||||
AuthMessageV4* = object {.packed.}
|
AuthMessageV4* = object {.packed.}
|
||||||
signature: RawSignature
|
signature: array[RawSignatureSize, byte]
|
||||||
keyhash: array[keccak256.sizeDigest, byte]
|
keyhash: array[keccak256.sizeDigest, byte]
|
||||||
pubkey: PublicKey
|
pubkey: PublicKey
|
||||||
nonce: array[keccak256.sizeDigest, byte]
|
nonce: array[keccak256.sizeDigest, byte]
|
||||||
flag: byte
|
flag: byte
|
||||||
|
|
||||||
AckMessageV4* = object {.packed.}
|
AckMessageV4* = object {.packed.}
|
||||||
pubkey: PublicKey
|
pubkey: array[RawPublicKeySize, byte]
|
||||||
nonce: array[keccak256.sizeDigest, byte]
|
nonce: array[keccak256.sizeDigest, byte]
|
||||||
flag: byte
|
flag: byte
|
||||||
|
|
||||||
|
@ -115,16 +117,17 @@ proc authMessagePreEIP8(h: var Handshake,
|
||||||
outlen = 0
|
outlen = 0
|
||||||
flagb = byte(flag)
|
flagb = byte(flag)
|
||||||
header = cast[ptr AuthMessageV4](addr buffer[0])
|
header = cast[ptr AuthMessageV4](addr buffer[0])
|
||||||
if ecdhAgree(h.host.seckey, pubkey, secret) != EccStatus.Success:
|
if ecdhAgree(h.host.seckey, pubkey, secret) != EthKeysStatus.Success:
|
||||||
return(EcdhError)
|
return(EcdhError)
|
||||||
var xornonce = h.initiatorNonce
|
var xornonce = h.initiatorNonce
|
||||||
xornonce.sxor(secret)
|
xornonce.sxor(secret.data)
|
||||||
if signMessage(h.ephemeral.seckey, xornonce, signature) != EccStatus.Success:
|
if signRawMessage(xornonce, h.ephemeral.seckey,
|
||||||
|
signature) != EthKeysStatus.Success:
|
||||||
return(SignatureError)
|
return(SignatureError)
|
||||||
h.remoteHPubkey = pubkey
|
h.remoteHPubkey = pubkey
|
||||||
header.signature = signature.getRaw()
|
header.signature = signature.getRaw()
|
||||||
header.keyhash = keccak256.digest(h.ephemeral.pubkey.getRaw().data).data
|
header.keyhash = keccak256.digest(h.ephemeral.pubkey.getRaw()).data
|
||||||
header.pubkey = cast[PublicKey](h.host.pubkey.getRaw().data)
|
header.pubkey = cast[PublicKey](h.host.pubkey.getRaw())
|
||||||
header.nonce = h.initiatorNonce
|
header.nonce = h.initiatorNonce
|
||||||
header.flag = flagb
|
header.flag = flagb
|
||||||
if encrypt:
|
if encrypt:
|
||||||
|
@ -156,15 +159,16 @@ proc authMessageEIP8(h: var Handshake,
|
||||||
|
|
||||||
assert(EIP8 in h.flags)
|
assert(EIP8 in h.flags)
|
||||||
outlen = 0
|
outlen = 0
|
||||||
if ecdhAgree(h.host.seckey, pubkey, secret) != EccStatus.Success:
|
if ecdhAgree(h.host.seckey, pubkey, secret) != EthKeysStatus.Success:
|
||||||
return(EcdhError)
|
return(EcdhError)
|
||||||
var xornonce = h.initiatorNonce
|
var xornonce = h.initiatorNonce
|
||||||
xornonce.sxor(secret)
|
xornonce.sxor(secret.data)
|
||||||
if signMessage(h.ephemeral.seckey, xornonce, signature) != EccStatus.Success:
|
if signRawMessage(xornonce, h.ephemeral.seckey,
|
||||||
|
signature) != EthKeysStatus.Success:
|
||||||
return(SignatureError)
|
return(SignatureError)
|
||||||
h.remoteHPubkey = pubkey
|
h.remoteHPubkey = pubkey
|
||||||
var payload = rlp.encodeList(signature.getRaw().data,
|
var payload = rlp.encodeList(signature.getRaw(),
|
||||||
h.host.pubkey.getRaw().data,
|
h.host.pubkey.getRaw(),
|
||||||
h.initiatorNonce,
|
h.initiatorNonce,
|
||||||
[byte(h.version)])
|
[byte(h.version)])
|
||||||
assert(len(payload) == PlainAuthMessageEIP8Length)
|
assert(len(payload) == PlainAuthMessageEIP8Length)
|
||||||
|
@ -208,7 +212,7 @@ proc ackMessagePreEIP8(h: var Handshake,
|
||||||
var buffer: array[PlainAckMessageV4Length, byte]
|
var buffer: array[PlainAckMessageV4Length, byte]
|
||||||
outlen = 0
|
outlen = 0
|
||||||
var header = cast[ptr AckMessageV4](addr buffer[0])
|
var header = cast[ptr AckMessageV4](addr buffer[0])
|
||||||
header.pubkey = cast[PublicKey](h.ephemeral.pubkey.getRaw().data)
|
header.pubkey = h.ephemeral.pubkey.getRaw()
|
||||||
header.nonce = h.responderNonce
|
header.nonce = h.responderNonce
|
||||||
header.flag = byte(flag)
|
header.flag = byte(flag)
|
||||||
if encrypt:
|
if encrypt:
|
||||||
|
@ -234,7 +238,7 @@ proc ackMessageEIP8(h: var Handshake,
|
||||||
buffer: array[PlainAckMessageMaxEIP8, byte]
|
buffer: array[PlainAckMessageMaxEIP8, byte]
|
||||||
padsize: byte
|
padsize: byte
|
||||||
assert(EIP8 in h.flags)
|
assert(EIP8 in h.flags)
|
||||||
var payload = rlp.encodeList(h.ephemeral.pubkey.getRaw().data,
|
var payload = rlp.encodeList(h.ephemeral.pubkey.getRaw(),
|
||||||
h.responderNonce,
|
h.responderNonce,
|
||||||
[byte(h.version)])
|
[byte(h.version)])
|
||||||
assert(len(payload) == PlainAckMessageEIP8Length)
|
assert(len(payload) == PlainAckMessageEIP8Length)
|
||||||
|
@ -316,14 +320,14 @@ proc decodeAuthMessageV4(h: var Handshake, m: openarray[byte]): AuthStatus =
|
||||||
if eciesDecrypt(m, buffer, h.host.seckey) != EciesStatus.Success:
|
if eciesDecrypt(m, buffer, h.host.seckey) != EciesStatus.Success:
|
||||||
return(EciesError)
|
return(EciesError)
|
||||||
var header = cast[ptr AuthMessageV4](addr buffer[0])
|
var header = cast[ptr AuthMessageV4](addr buffer[0])
|
||||||
if recoverPublicKey(header.pubkey.data, pubkey) != EccStatus.Success:
|
if recoverPublicKey(header.pubkey.data, pubkey) != EthKeysStatus.Success:
|
||||||
return(InvalidPubKey)
|
return(InvalidPubKey)
|
||||||
if ecdhAgree(h.host.seckey, pubkey, secret) != EccStatus.Success:
|
if ecdhAgree(h.host.seckey, pubkey, secret) != EthKeysStatus.Success:
|
||||||
return(EcdhError)
|
return(EcdhError)
|
||||||
var xornonce = header.nonce
|
var xornonce = header.nonce
|
||||||
xornonce.sxor(secret)
|
xornonce.sxor(secret.data)
|
||||||
if recoverSignatureKey(header.signature.data, xornonce,
|
if recoverSignatureKey(header.signature, xornonce,
|
||||||
h.remoteEPubkey) != EccStatus.Success:
|
h.remoteEPubkey) != EthKeysStatus.Success:
|
||||||
return(SignatureError)
|
return(SignatureError)
|
||||||
h.initiatorNonce = header.nonce
|
h.initiatorNonce = header.nonce
|
||||||
h.remoteHPubkey = pubkey
|
h.remoteHPubkey = pubkey
|
||||||
|
@ -347,9 +351,9 @@ proc decodeAuthMessageEip8(h: var Handshake, m: openarray[byte]): AuthStatus =
|
||||||
var reader = rlpFromBytes(buffer.toRange())
|
var reader = rlpFromBytes(buffer.toRange())
|
||||||
if not reader.isList() or reader.listLen() < 4:
|
if not reader.isList() or reader.listLen() < 4:
|
||||||
return(InvalidAuth)
|
return(InvalidAuth)
|
||||||
if reader.listElem(0).blobLen != SignatureLength:
|
if reader.listElem(0).blobLen != RawSignatureSize:
|
||||||
return(InvalidAuth)
|
return(InvalidAuth)
|
||||||
if reader.listElem(1).blobLen != PublicKeyLength:
|
if reader.listElem(1).blobLen != RawPublicKeySize:
|
||||||
return(InvalidAuth)
|
return(InvalidAuth)
|
||||||
if reader.listElem(2).blobLen != KeyLength:
|
if reader.listElem(2).blobLen != KeyLength:
|
||||||
return(InvalidAuth)
|
return(InvalidAuth)
|
||||||
|
@ -359,17 +363,17 @@ proc decodeAuthMessageEip8(h: var Handshake, m: openarray[byte]): AuthStatus =
|
||||||
var pubkeyBr = reader.listElem(1).toBytes()
|
var pubkeyBr = reader.listElem(1).toBytes()
|
||||||
var nonceBr = reader.listElem(2).toBytes()
|
var nonceBr = reader.listElem(2).toBytes()
|
||||||
var versionBr = reader.listElem(3).toBytes()
|
var versionBr = reader.listElem(3).toBytes()
|
||||||
if recoverPublicKey(pubkeyBr.baseAddr, PublicKeyLength,
|
if recoverPublicKey(pubkeyBr.toOpenArray(),
|
||||||
pubkey) != EccStatus.Success:
|
pubkey) != EthKeysStatus.Success:
|
||||||
return(InvalidPubKey)
|
return(InvalidPubKey)
|
||||||
copyMem(addr nonce[0], nonceBr.baseAddr, KeyLength)
|
copyMem(addr nonce[0], nonceBr.baseAddr, KeyLength)
|
||||||
if ecdhAgree(h.host.seckey, pubkey, secret) != EccStatus.Success:
|
if ecdhAgree(h.host.seckey, pubkey, secret) != EthKeysStatus.Success:
|
||||||
return(EcdhError)
|
return(EcdhError)
|
||||||
var xornonce = nonce
|
var xornonce = nonce
|
||||||
xornonce.sxor(secret)
|
xornonce.sxor(secret.data)
|
||||||
if recoverSignatureKey(signatureBr.baseAddr, SignatureLength,
|
if recoverSignatureKey(signatureBr.toOpenArray(),
|
||||||
addr xornonce[0],
|
xornonce,
|
||||||
h.remoteEPubkey) != EccStatus.Success:
|
h.remoteEPubkey) != EthKeysStatus.Success:
|
||||||
return(SignatureError)
|
return(SignatureError)
|
||||||
h.initiatorNonce = nonce
|
h.initiatorNonce = nonce
|
||||||
h.remoteHPubkey = pubkey
|
h.remoteHPubkey = pubkey
|
||||||
|
@ -393,7 +397,7 @@ proc decodeAckMessageEip8*(h: var Handshake, m: openarray[byte]): AuthStatus =
|
||||||
var reader = rlpFromBytes(buffer.toRange())
|
var reader = rlpFromBytes(buffer.toRange())
|
||||||
if not reader.isList() or reader.listLen() < 3:
|
if not reader.isList() or reader.listLen() < 3:
|
||||||
return(InvalidAck)
|
return(InvalidAck)
|
||||||
if reader.listElem(0).blobLen != PublicKeyLength:
|
if reader.listElem(0).blobLen != RawPublicKeySize:
|
||||||
return(InvalidAck)
|
return(InvalidAck)
|
||||||
if reader.listElem(1).blobLen != KeyLength:
|
if reader.listElem(1).blobLen != KeyLength:
|
||||||
return(InvalidAck)
|
return(InvalidAck)
|
||||||
|
@ -402,8 +406,8 @@ proc decodeAckMessageEip8*(h: var Handshake, m: openarray[byte]): AuthStatus =
|
||||||
let pubkeyBr = reader.listElem(0).toBytes()
|
let pubkeyBr = reader.listElem(0).toBytes()
|
||||||
let nonceBr = reader.listElem(1).toBytes()
|
let nonceBr = reader.listElem(1).toBytes()
|
||||||
let versionBr = reader.listElem(2).toBytes()
|
let versionBr = reader.listElem(2).toBytes()
|
||||||
if recoverPublicKey(pubkeyBr.baseAddr, PublicKeyLength,
|
if recoverPublicKey(pubkeyBr.toOpenArray(),
|
||||||
h.remoteEPubkey) != EccStatus.Success:
|
h.remoteEPubkey) != EthKeysStatus.Success:
|
||||||
return(InvalidPubKey)
|
return(InvalidPubKey)
|
||||||
copyMem(addr h.responderNonce[0], nonceBr.baseAddr, KeyLength)
|
copyMem(addr h.responderNonce[0], nonceBr.baseAddr, KeyLength)
|
||||||
h.version = cast[ptr byte](versionBr.baseAddr)[]
|
h.version = cast[ptr byte](versionBr.baseAddr)[]
|
||||||
|
@ -419,7 +423,7 @@ proc decodeAckMessageV4(h: var Handshake, m: openarray[byte]): AuthStatus =
|
||||||
if eciesDecrypt(m, buffer, h.host.seckey) != EciesStatus.Success:
|
if eciesDecrypt(m, buffer, h.host.seckey) != EciesStatus.Success:
|
||||||
return(EciesError)
|
return(EciesError)
|
||||||
var header = cast[ptr AckMessageV4](addr buffer[0])
|
var header = cast[ptr AckMessageV4](addr buffer[0])
|
||||||
if recoverPublicKey(header.pubkey.data, h.remoteEPubkey) != EccStatus.Success:
|
if recoverPublicKey(header.pubkey, h.remoteEPubkey) != EthKeysStatus.Success:
|
||||||
return(InvalidPubKey)
|
return(InvalidPubKey)
|
||||||
h.responderNonce = header.nonce
|
h.responderNonce = header.nonce
|
||||||
result = Success
|
result = Success
|
||||||
|
@ -476,7 +480,8 @@ proc getSecrets*(h: Handshake, authmsg: openarray[byte],
|
||||||
xornonce: Nonce
|
xornonce: Nonce
|
||||||
|
|
||||||
# ecdhe-secret = ecdh.agree(ephemeral-privkey, remote-ephemeral-pubk)
|
# ecdhe-secret = ecdh.agree(ephemeral-privkey, remote-ephemeral-pubk)
|
||||||
if ecdhAgree(h.ephemeral.seckey, h.remoteEPubkey, shsec) != EccStatus.Success:
|
if ecdhAgree(h.ephemeral.seckey, h.remoteEPubkey,
|
||||||
|
shsec) != EthKeysStatus.Success:
|
||||||
return(EcdhError)
|
return(EcdhError)
|
||||||
|
|
||||||
# shared-secret = keccak(ecdhe-secret || keccak(nonce || initiator-nonce))
|
# shared-secret = keccak(ecdhe-secret || keccak(nonce || initiator-nonce))
|
||||||
|
@ -486,19 +491,19 @@ proc getSecrets*(h: Handshake, authmsg: openarray[byte],
|
||||||
ctx1.update(h.initiatorNonce)
|
ctx1.update(h.initiatorNonce)
|
||||||
mac1 = ctx1.finish()
|
mac1 = ctx1.finish()
|
||||||
ctx1.clear()
|
ctx1.clear()
|
||||||
ctx0.update(shsec)
|
ctx0.update(shsec.data)
|
||||||
ctx0.update(mac1.data)
|
ctx0.update(mac1.data)
|
||||||
mac1 = ctx0.finish()
|
mac1 = ctx0.finish()
|
||||||
|
|
||||||
# aes-secret = keccak(ecdhe-secret || shared-secret)
|
# aes-secret = keccak(ecdhe-secret || shared-secret)
|
||||||
ctx0.init()
|
ctx0.init()
|
||||||
ctx0.update(shsec)
|
ctx0.update(shsec.data)
|
||||||
ctx0.update(mac1.data)
|
ctx0.update(mac1.data)
|
||||||
mac1 = ctx0.finish()
|
mac1 = ctx0.finish()
|
||||||
|
|
||||||
# mac-secret = keccak(ecdhe-secret || aes-secret)
|
# mac-secret = keccak(ecdhe-secret || aes-secret)
|
||||||
ctx0.init()
|
ctx0.init()
|
||||||
ctx0.update(shsec)
|
ctx0.update(shsec.data)
|
||||||
ctx0.update(mac1.data)
|
ctx0.update(mac1.data)
|
||||||
secret.aesKey = mac1.data
|
secret.aesKey = mac1.data
|
||||||
mac1 = ctx0.finish()
|
mac1 = ctx0.finish()
|
||||||
|
|
323
ethp2p/ecc.nim
323
ethp2p/ecc.nim
|
@ -1,323 +0,0 @@
|
||||||
#
|
|
||||||
# Ethereum P2P
|
|
||||||
# (c) Copyright 2018
|
|
||||||
# Status Research & Development GmbH
|
|
||||||
#
|
|
||||||
# See the file "LICENSE", included in this
|
|
||||||
# distribution, for details about the copyright.
|
|
||||||
#
|
|
||||||
|
|
||||||
## This module implements `libsecp256k1` ECC/ECDH functions
|
|
||||||
|
|
||||||
import secp256k1, hexdump, nimcrypto/sysrand, nimcrypto/utils
|
|
||||||
|
|
||||||
const
|
|
||||||
KeyLength* = 32
|
|
||||||
PublicKeyLength* = 64
|
|
||||||
SignatureLength* = 65
|
|
||||||
|
|
||||||
type
|
|
||||||
EccContext* = ref object of RootRef
|
|
||||||
context*: ptr secp256k1_context
|
|
||||||
error*: string
|
|
||||||
|
|
||||||
EccStatus* = enum
|
|
||||||
Success, ## Operation was successful
|
|
||||||
Error ## Operation failed
|
|
||||||
|
|
||||||
PublicKey* = secp256k1_pubkey
|
|
||||||
## Representation of public key
|
|
||||||
|
|
||||||
PrivateKey* = array[KeyLength, byte]
|
|
||||||
## Representation of secret key
|
|
||||||
|
|
||||||
SharedSecret* = array[KeyLength, byte]
|
|
||||||
## Representation of ECDH shared secret
|
|
||||||
|
|
||||||
Nonce* = array[KeyLength, byte]
|
|
||||||
## Representation of nonce
|
|
||||||
|
|
||||||
RawPublickey* = object
|
|
||||||
## Representation of serialized public key
|
|
||||||
header*: byte
|
|
||||||
data*: array[KeyLength * 2, byte]
|
|
||||||
|
|
||||||
KeyPair* = object
|
|
||||||
## Representation of private/public keys pair
|
|
||||||
seckey*: PrivateKey
|
|
||||||
pubkey*: PublicKey
|
|
||||||
|
|
||||||
Signature* = secp256k1_ecdsa_recoverable_signature
|
|
||||||
## Representation of signature
|
|
||||||
|
|
||||||
RawSignature* = object
|
|
||||||
## Representation of serialized signature
|
|
||||||
data*: array[KeyLength * 2 + 1, byte]
|
|
||||||
|
|
||||||
Secp256k1Exception* = object of Exception
|
|
||||||
## Exceptions generated by `libsecp256k1`
|
|
||||||
EccException* = object of Exception
|
|
||||||
## Exception generated by this module
|
|
||||||
|
|
||||||
var eccContext* {.threadvar.}: EccContext
|
|
||||||
## Thread local variable which holds current context
|
|
||||||
|
|
||||||
proc illegalCallback(message: cstring; data: pointer) {.cdecl.} =
|
|
||||||
let ctx = cast[EccContext](data)
|
|
||||||
ctx.error = $message
|
|
||||||
|
|
||||||
proc errorCallback(message: cstring, data: pointer) {.cdecl.} =
|
|
||||||
let ctx = cast[EccContext](data)
|
|
||||||
ctx.error = $message
|
|
||||||
|
|
||||||
proc newEccContext*(): EccContext =
|
|
||||||
## Create new `EccContext`.
|
|
||||||
result = new EccContext
|
|
||||||
let flags = cuint(SECP256K1_CONTEXT_VERIFY or SECP256K1_CONTEXT_SIGN)
|
|
||||||
result.context = secp256k1_context_create(flags)
|
|
||||||
secp256k1_context_set_illegal_callback(result.context, illegalCallback,
|
|
||||||
cast[pointer](result))
|
|
||||||
secp256k1_context_set_error_callback(result.context, errorCallback,
|
|
||||||
cast[pointer](result))
|
|
||||||
result.error = ""
|
|
||||||
|
|
||||||
proc getSecpContext*(): ptr secp256k1_context =
|
|
||||||
## Get current `secp256k1_context`
|
|
||||||
if isNil(eccContext):
|
|
||||||
eccContext = newEccContext()
|
|
||||||
result = eccContext.context
|
|
||||||
|
|
||||||
proc getEccContext*(): EccContext =
|
|
||||||
## Get current `EccContext`
|
|
||||||
if isNil(eccContext):
|
|
||||||
eccContext = newEccContext()
|
|
||||||
result = eccContext
|
|
||||||
|
|
||||||
template raiseSecp256k1Error*() =
|
|
||||||
## Raises `libsecp256k1` error as exception
|
|
||||||
let mctx = getEccContext()
|
|
||||||
if len(mctx.error) > 0:
|
|
||||||
var msg = mctx.error
|
|
||||||
mctx.error.setLen(0)
|
|
||||||
raise newException(Secp256k1Exception, msg)
|
|
||||||
|
|
||||||
proc eccErrorMsg*(): string =
|
|
||||||
let mctx = getEccContext()
|
|
||||||
result = mctx.error
|
|
||||||
|
|
||||||
proc setErrorMsg*(m: string) =
|
|
||||||
let mctx = getEccContext()
|
|
||||||
mctx.error = m
|
|
||||||
|
|
||||||
proc getRaw*(pubkey: PublicKey): RawPublickey =
|
|
||||||
## Converts public key `pubkey` to serialized form of `secp256k1_pubkey`.
|
|
||||||
var length = csize(sizeof(RawPublickey))
|
|
||||||
let ctx = getSecpContext()
|
|
||||||
if secp256k1_ec_pubkey_serialize(ctx, cast[ptr cuchar](addr result),
|
|
||||||
addr length, unsafeAddr pubkey,
|
|
||||||
SECP256K1_EC_UNCOMPRESSED) != 1:
|
|
||||||
raiseSecp256k1Error()
|
|
||||||
if length != 65:
|
|
||||||
raise newException(EccException, "Invalid public key length!")
|
|
||||||
if result.header != 0x04'u8:
|
|
||||||
raise newException(EccException, "Invalid public key header!")
|
|
||||||
|
|
||||||
proc getRaw*(s: Signature): RawSignature =
|
|
||||||
## 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.data[64] = uint8(recid)
|
|
||||||
|
|
||||||
proc signMessage*(seckey: PrivateKey, data: ptr byte, length: int,
|
|
||||||
sig: var Signature): EccStatus =
|
|
||||||
## Sign message pointed by `data` with size `length` and save signature to
|
|
||||||
## `sig`.
|
|
||||||
let ctx = getSecpContext()
|
|
||||||
if secp256k1_ecdsa_sign_recoverable(ctx, addr sig,
|
|
||||||
cast[ptr cuchar](data),
|
|
||||||
cast[ptr cuchar](unsafeAddr seckey[0]),
|
|
||||||
nil, nil) != 1:
|
|
||||||
return(Error)
|
|
||||||
return(Success)
|
|
||||||
|
|
||||||
proc signMessage*[T](seckey: PrivateKey, data: openarray[T],
|
|
||||||
sig: var Signature, ostart: int = 0,
|
|
||||||
ofinish: int = -1): EccStatus =
|
|
||||||
## Sign message ``data``[`soffset`..`eoffset`] and store result into `sig`.
|
|
||||||
let so = ostart
|
|
||||||
let eo = if ofinish == -1: (len(data) - 1) else: ofinish
|
|
||||||
let length = (eo - so + 1) * sizeof(T)
|
|
||||||
# We don't need to check `so` because compiler will do it for `data[so]`.
|
|
||||||
if eo >= len(data):
|
|
||||||
setErrorMsg("Index is out of bounds!")
|
|
||||||
return(Error)
|
|
||||||
if len(data) < KeyLength or length < KeyLength:
|
|
||||||
setErrorMsg("There no reason to sign this message!")
|
|
||||||
return(Error)
|
|
||||||
result = signMessage(seckey, cast[ptr byte](unsafeAddr data[so]),
|
|
||||||
length, sig)
|
|
||||||
|
|
||||||
proc recoverSignatureKey*(data: ptr byte, length: int, message: ptr byte,
|
|
||||||
pubkey: var PublicKey): EccStatus =
|
|
||||||
## Check signature and return public key from `data` with size `length` and
|
|
||||||
## `message`.
|
|
||||||
let ctx = getSecpContext()
|
|
||||||
var s: secp256k1_ecdsa_recoverable_signature
|
|
||||||
if length >= 65:
|
|
||||||
var recid = cint(cast[ptr UncheckedArray[byte]](data)[KeyLength * 2])
|
|
||||||
if secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, addr s,
|
|
||||||
cast[ptr cuchar](data),
|
|
||||||
recid) != 1:
|
|
||||||
return(Error)
|
|
||||||
|
|
||||||
if secp256k1_ecdsa_recover(ctx, addr pubkey, addr s,
|
|
||||||
cast[ptr cuchar](message)) != 1:
|
|
||||||
setErrorMsg("Message signature verification failed!")
|
|
||||||
return(Error)
|
|
||||||
return(Success)
|
|
||||||
else:
|
|
||||||
setErrorMsg("Incorrect signature size")
|
|
||||||
return(Error)
|
|
||||||
|
|
||||||
proc recoverSignatureKey*[A, B](data: openarray[A],
|
|
||||||
message: openarray[B],
|
|
||||||
pubkey: var PublicKey,
|
|
||||||
ostart: int = 0,
|
|
||||||
ofinish: int = -1): EccStatus =
|
|
||||||
## Check signature in ``data``[`soffset`..`eoffset`] and recover public key
|
|
||||||
## from signature to ``pubkey`` using message `message`.
|
|
||||||
if len(message) == 0:
|
|
||||||
setErrorMsg("Message could not be empty!")
|
|
||||||
return(Error)
|
|
||||||
let so = ostart
|
|
||||||
let eo = if ofinish == -1: (len(data) - 1) else: ofinish
|
|
||||||
let length = (eo - so + 1) * sizeof(A)
|
|
||||||
# We don't need to check `so` because compiler will do it for `data[so]`.
|
|
||||||
if eo > len(data):
|
|
||||||
setErrorMsg("Index is out of bounds!")
|
|
||||||
return(Error)
|
|
||||||
if length < sizeof(RawSignature) or len(data) < sizeof(RawSignature):
|
|
||||||
setErrorMsg("Invalid signature size!")
|
|
||||||
return(Error)
|
|
||||||
result = recoverSignatureKey(cast[ptr byte](unsafeAddr data[so]), length,
|
|
||||||
cast[ptr byte](unsafeAddr message[0]), pubkey)
|
|
||||||
|
|
||||||
proc ecdhAgree*(seckey: PrivateKey, pubkey: PublicKey,
|
|
||||||
secret: var SharedSecret): EccStatus =
|
|
||||||
## Calculate ECDH shared secret
|
|
||||||
var res: array[KeyLength + 1, byte]
|
|
||||||
let ctx = getSecpContext()
|
|
||||||
if secp256k1_ecdh_raw(ctx, cast[ptr cuchar](addr res),
|
|
||||||
unsafeAddr pubkey,
|
|
||||||
cast[ptr cuchar](unsafeAddr seckey)) != 1:
|
|
||||||
return(Error)
|
|
||||||
copyMem(addr secret[0], addr res[1], KeyLength)
|
|
||||||
return(Success)
|
|
||||||
|
|
||||||
proc getPublicKey*(seckey: PrivateKey): PublicKey =
|
|
||||||
## Return public key for private key `seckey`.
|
|
||||||
let ctx = getSecpContext()
|
|
||||||
if secp256k1_ec_pubkey_create(ctx, addr result,
|
|
||||||
cast[ptr cuchar](unsafeAddr seckey[0])) != 1:
|
|
||||||
raiseSecp256k1Error()
|
|
||||||
|
|
||||||
|
|
||||||
proc recoverPublicKey*(data: ptr byte, length: int,
|
|
||||||
pubkey: var PublicKey): EccStatus =
|
|
||||||
## Unserialize public key from `data` pointer and size `length` and'
|
|
||||||
## set `pubkey`.
|
|
||||||
let ctx = getSecpContext()
|
|
||||||
if length < sizeof(PublicKey):
|
|
||||||
setErrorMsg("Invalid public key!")
|
|
||||||
return(Error)
|
|
||||||
var rawkey: RawPublickey
|
|
||||||
rawkey.header = 0x04 # mark key with COMPRESSED flag
|
|
||||||
copyMem(addr rawkey.data[0], data, len(rawkey.data))
|
|
||||||
if secp256k1_ec_pubkey_parse(ctx, addr pubkey,
|
|
||||||
cast[ptr cuchar](addr rawkey),
|
|
||||||
sizeof(RawPublickey)) != 1:
|
|
||||||
return(Error)
|
|
||||||
return(Success)
|
|
||||||
|
|
||||||
proc recoverPublicKey*[T](data: openarray[T], pubkey: var PublicKey,
|
|
||||||
ostart: int = 0, ofinish: int = -1, ): EccStatus =
|
|
||||||
## Unserialize public key from openarray[T] `data`, from position `ostart` to
|
|
||||||
## position `ofinish` and save it to `pubkey`.
|
|
||||||
let so = ostart
|
|
||||||
let eo = if ofinish == -1: (len(data) - 1) else: ofinish
|
|
||||||
let length = (eo - so + 1) * sizeof(T)
|
|
||||||
# We don't need to check `so` because compiler will do it for `data[so]`.
|
|
||||||
if eo > len(data):
|
|
||||||
setErrorMsg("Index is out of bounds!")
|
|
||||||
return(Error)
|
|
||||||
if length < sizeof(PublicKey) or len(data) < sizeof(PublicKey):
|
|
||||||
setErrorMsg("Invalid public key size!")
|
|
||||||
return(Error)
|
|
||||||
result = recoverPublicKey(cast[ptr byte](unsafeAddr data[so]), length,
|
|
||||||
pubkey)
|
|
||||||
|
|
||||||
proc newPrivateKey*(): PrivateKey =
|
|
||||||
## Generates new secret key.
|
|
||||||
let ctx = getSecpContext()
|
|
||||||
while true:
|
|
||||||
if randomBytes(result) == KeyLength:
|
|
||||||
if secp256k1_ec_seckey_verify(ctx, cast[ptr cuchar](addr result[0])) == 1:
|
|
||||||
break
|
|
||||||
|
|
||||||
proc newKeyPair*(): KeyPair =
|
|
||||||
## Generates new private and public key.
|
|
||||||
result.seckey = newPrivateKey()
|
|
||||||
result.pubkey = result.seckey.getPublicKey()
|
|
||||||
|
|
||||||
proc getPrivateKey*(hexstr: string): PrivateKey =
|
|
||||||
## Set secret key from hexadecimal string representation.
|
|
||||||
let ctx = getSecpContext()
|
|
||||||
var o = fromHex(stripSpaces(hexstr))
|
|
||||||
if len(o) < KeyLength:
|
|
||||||
raise newException(EccException, "Invalid private key!")
|
|
||||||
copyMem(addr result[0], unsafeAddr o[0], KeyLength)
|
|
||||||
if secp256k1_ec_seckey_verify(ctx, cast[ptr cuchar](addr result[0])) != 1:
|
|
||||||
raise newException(EccException, "Invalid private key!")
|
|
||||||
|
|
||||||
proc getPublicKey*(hexstr: string): PublicKey =
|
|
||||||
## Set public key from hexadecimal string representation.
|
|
||||||
var o = fromHex(stripSpaces(hexstr))
|
|
||||||
if recoverPublicKey(o, result) != Success:
|
|
||||||
raise newException(EccException, "Invalid public key!")
|
|
||||||
|
|
||||||
proc dump*(s: openarray[byte], c: string = ""): string =
|
|
||||||
## Return hexadecimal dump of array `s`.
|
|
||||||
result = if len(c) > 0: c & "=>\n" else: ""
|
|
||||||
if len(s) > 0:
|
|
||||||
result &= dumpHex(unsafeAddr s[0], len(s))
|
|
||||||
else:
|
|
||||||
result &= "[]"
|
|
||||||
|
|
||||||
proc dump*(s: PublicKey, c: string = ""): string =
|
|
||||||
## Return hexadecimal dump of public key `s`.
|
|
||||||
result = if len(c) > 0: c & "=>\n" else: ""
|
|
||||||
result &= dumpHex(unsafeAddr s.data[0], sizeof(secp256k1_pubkey))
|
|
||||||
|
|
||||||
proc dump*(s: RawSignature, c: string = ""): string =
|
|
||||||
## Return hexadecimal dump of serialized signature `s`.
|
|
||||||
result = if len(c) > 0: c & "=>\n" else: ""
|
|
||||||
result &= dumpHex(unsafeAddr s.data[0], sizeof(RawSignature))
|
|
||||||
|
|
||||||
proc dump*(s: RawPublickey, c: string = ""): string =
|
|
||||||
## Return hexadecimal dump of serialized public key `s`.
|
|
||||||
result = if len(c) > 0: c & "=>\n" else: ""
|
|
||||||
result &= dumpHex(unsafeAddr s, sizeof(RawSignature))
|
|
||||||
|
|
||||||
proc dump*(s: secp256k1_ecdsa_recoverable_signature, c: string = ""): string =
|
|
||||||
## Return hexadecimal dump of signature `s`.
|
|
||||||
result = if len(c) > 0: c & "=>\n" else: ""
|
|
||||||
result &= dumpHex(unsafeAddr s.data[0],
|
|
||||||
sizeof(secp256k1_ecdsa_recoverable_signature))
|
|
||||||
|
|
||||||
proc dump*(p: pointer, s: int, c: string = ""): string =
|
|
||||||
## Return hexadecimal dump of memory blob `p` and size `s`.
|
|
||||||
result = if len(c) > 0: c & "=>\n" else: ""
|
|
||||||
result &= dumpHex(p, s)
|
|
|
@ -9,7 +9,8 @@
|
||||||
|
|
||||||
## This module implements ECIES method encryption/decryption.
|
## This module implements ECIES method encryption/decryption.
|
||||||
|
|
||||||
import ecc, nimcrypto/sha2, nimcrypto/hash, nimcrypto/hmac
|
import eth_keys
|
||||||
|
import nimcrypto/sha2, nimcrypto/hash, nimcrypto/hmac
|
||||||
import nimcrypto/rijndael, nimcrypto/utils, nimcrypto/sysrand
|
import nimcrypto/rijndael, nimcrypto/utils, nimcrypto/sysrand
|
||||||
import nimcrypto/bcmode, nimcrypto/utils
|
import nimcrypto/bcmode, nimcrypto/utils
|
||||||
|
|
||||||
|
@ -30,7 +31,7 @@ type
|
||||||
|
|
||||||
EciesHeader* = object {.packed.}
|
EciesHeader* = object {.packed.}
|
||||||
version*: byte
|
version*: byte
|
||||||
pubkey*: array[PublicKeyLength, byte]
|
pubkey*: array[RawPublicKeySize, byte]
|
||||||
iv*: array[aes128.sizeBlock, byte]
|
iv*: array[aes128.sizeBlock, byte]
|
||||||
data*: byte
|
data*: byte
|
||||||
|
|
||||||
|
@ -109,12 +110,11 @@ proc eciesEncrypt*(input: openarray[byte], output: var openarray[byte],
|
||||||
return(RandomError)
|
return(RandomError)
|
||||||
|
|
||||||
var ephemeral = newKeyPair()
|
var ephemeral = newKeyPair()
|
||||||
var epub = ephemeral.pubkey.getRaw()
|
|
||||||
|
|
||||||
if ecdhAgree(ephemeral.seckey, pubkey, secret) != EccStatus.Success:
|
if ecdhAgree(ephemeral.seckey, pubkey, secret) != EthKeysStatus.Success:
|
||||||
return(EcdhError)
|
return(EcdhError)
|
||||||
|
|
||||||
material = kdf(secret)
|
material = kdf(secret.data)
|
||||||
burnMem(secret)
|
burnMem(secret)
|
||||||
|
|
||||||
copyMem(addr encKey[0], addr material[0], aes128.sizeKey)
|
copyMem(addr encKey[0], addr material[0], aes128.sizeKey)
|
||||||
|
@ -123,7 +123,7 @@ proc eciesEncrypt*(input: openarray[byte], output: var openarray[byte],
|
||||||
|
|
||||||
var header = cast[ptr EciesHeader](addr output[0])
|
var header = cast[ptr EciesHeader](addr output[0])
|
||||||
header.version = 0x04
|
header.version = 0x04
|
||||||
header.pubkey = epub.data
|
header.pubkey = ephemeral.pubkey.getRaw()
|
||||||
header.iv = iv
|
header.iv = iv
|
||||||
|
|
||||||
var so = eciesDataPos()
|
var so = eciesDataPos()
|
||||||
|
@ -176,12 +176,12 @@ proc eciesDecrypt*(input: openarray[byte],
|
||||||
return(IncompleteError)
|
return(IncompleteError)
|
||||||
if len(input) - eciesOverheadLength() > len(output):
|
if len(input) - eciesOverheadLength() > len(output):
|
||||||
return(BufferOverrun)
|
return(BufferOverrun)
|
||||||
if recoverPublicKey(header.pubkey, pubkey) != EccStatus.Success:
|
if recoverPublicKey(header.pubkey, pubkey) != EthKeysStatus.Success:
|
||||||
return(IncorrectKey)
|
return(IncorrectKey)
|
||||||
if ecdhAgree(seckey, pubkey, secret) != EccStatus.Success:
|
if ecdhAgree(seckey, pubkey, secret) != EthKeysStatus.Success:
|
||||||
return(EcdhError)
|
return(EcdhError)
|
||||||
|
|
||||||
var material = kdf(secret)
|
var material = kdf(secret.data)
|
||||||
burnMem(secret)
|
burnMem(secret)
|
||||||
copyMem(addr encKey[0], addr material[0], aes128.sizeKey)
|
copyMem(addr encKey[0], addr material[0], aes128.sizeKey)
|
||||||
var macKey = sha256.digest(material, ostart = KeyLength div 2)
|
var macKey = sha256.digest(material, ostart = KeyLength div 2)
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
#
|
#
|
||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
import ethp2p/ecc, ethp2p/auth, nimcrypto/utils
|
import eth_keys, ethp2p/auth, nimcrypto/utils
|
||||||
|
|
||||||
# This was generated by `print` actual auth message generated by
|
# This was generated by `print` actual auth message generated by
|
||||||
# https://github.com/ethereum/py-evm/blob/master/tests/p2p/test_auth.py
|
# https://github.com/ethereum/py-evm/blob/master/tests/p2p/test_auth.py
|
||||||
|
@ -216,18 +216,18 @@ suite "Ethereum P2P handshake test suite":
|
||||||
proc newTestHandshake(flags: set[HandshakeFlag]): Handshake =
|
proc newTestHandshake(flags: set[HandshakeFlag]): Handshake =
|
||||||
result = newHandshake(flags)
|
result = newHandshake(flags)
|
||||||
if Initiator in flags:
|
if Initiator in flags:
|
||||||
result.host.seckey = getPrivateKey(testValue("initiator_private_key"))
|
result.host.seckey = initPrivateKey(testValue("initiator_private_key"))
|
||||||
result.host.pubkey = result.host.seckey.getPublicKey()
|
result.host.pubkey = result.host.seckey.getPublicKey()
|
||||||
let epki = testValue("initiator_ephemeral_private_key")
|
let epki = testValue("initiator_ephemeral_private_key")
|
||||||
result.ephemeral.seckey = getPrivateKey(epki)
|
result.ephemeral.seckey = initPrivateKey(epki)
|
||||||
result.ephemeral.pubkey = result.ephemeral.seckey.getPublicKey()
|
result.ephemeral.pubkey = result.ephemeral.seckey.getPublicKey()
|
||||||
let nonce = fromHex(stripSpaces(testValue("initiator_nonce")))
|
let nonce = fromHex(stripSpaces(testValue("initiator_nonce")))
|
||||||
result.initiatorNonce[0..^1] = nonce[0..^1]
|
result.initiatorNonce[0..^1] = nonce[0..^1]
|
||||||
elif Responder in flags:
|
elif Responder in flags:
|
||||||
result.host.seckey = getPrivateKey(testValue("receiver_private_key"))
|
result.host.seckey = initPrivateKey(testValue("receiver_private_key"))
|
||||||
result.host.pubkey = result.host.seckey.getPublicKey()
|
result.host.pubkey = result.host.seckey.getPublicKey()
|
||||||
let epkr = testValue("receiver_ephemeral_private_key")
|
let epkr = testValue("receiver_ephemeral_private_key")
|
||||||
result.ephemeral.seckey = getPrivateKey(epkr)
|
result.ephemeral.seckey = initPrivateKey(epkr)
|
||||||
result.ephemeral.pubkey = result.ephemeral.seckey.getPublicKey()
|
result.ephemeral.pubkey = result.ephemeral.seckey.getPublicKey()
|
||||||
let nonce = fromHex(stripSpaces(testValue("receiver_nonce")))
|
let nonce = fromHex(stripSpaces(testValue("receiver_nonce")))
|
||||||
result.responderNonce[0..^1] = nonce[0..^1]
|
result.responderNonce[0..^1] = nonce[0..^1]
|
||||||
|
@ -326,18 +326,18 @@ suite "Ethereum P2P handshake test suite":
|
||||||
proc newTestHandshake(flags: set[HandshakeFlag]): Handshake =
|
proc newTestHandshake(flags: set[HandshakeFlag]): Handshake =
|
||||||
result = newHandshake(flags)
|
result = newHandshake(flags)
|
||||||
if Initiator in flags:
|
if Initiator in flags:
|
||||||
result.host.seckey = getPrivateKey(testE8Value("initiator_private_key"))
|
result.host.seckey = initPrivateKey(testE8Value("initiator_private_key"))
|
||||||
result.host.pubkey = result.host.seckey.getPublicKey()
|
result.host.pubkey = result.host.seckey.getPublicKey()
|
||||||
let esec = testE8Value("initiator_ephemeral_private_key")
|
let esec = testE8Value("initiator_ephemeral_private_key")
|
||||||
result.ephemeral.seckey = getPrivateKey(esec)
|
result.ephemeral.seckey = initPrivateKey(esec)
|
||||||
result.ephemeral.pubkey = result.ephemeral.seckey.getPublicKey()
|
result.ephemeral.pubkey = result.ephemeral.seckey.getPublicKey()
|
||||||
let nonce = fromHex(stripSpaces(testE8Value("initiator_nonce")))
|
let nonce = fromHex(stripSpaces(testE8Value("initiator_nonce")))
|
||||||
result.initiatorNonce[0..^1] = nonce[0..^1]
|
result.initiatorNonce[0..^1] = nonce[0..^1]
|
||||||
elif Responder in flags:
|
elif Responder in flags:
|
||||||
result.host.seckey = getPrivateKey(testE8Value("receiver_private_key"))
|
result.host.seckey = initPrivateKey(testE8Value("receiver_private_key"))
|
||||||
result.host.pubkey = result.host.seckey.getPublicKey()
|
result.host.pubkey = result.host.seckey.getPublicKey()
|
||||||
let esec = testE8Value("receiver_ephemeral_private_key")
|
let esec = testE8Value("receiver_ephemeral_private_key")
|
||||||
result.ephemeral.seckey = getPrivateKey(esec)
|
result.ephemeral.seckey = initPrivateKey(esec)
|
||||||
result.ephemeral.pubkey = result.ephemeral.seckey.getPublicKey()
|
result.ephemeral.pubkey = result.ephemeral.seckey.getPublicKey()
|
||||||
let nonce = fromHex(stripSpaces(testE8Value("receiver_nonce")))
|
let nonce = fromHex(stripSpaces(testE8Value("receiver_nonce")))
|
||||||
result.responderNonce[0..^1] = nonce[0..^1]
|
result.responderNonce[0..^1] = nonce[0..^1]
|
||||||
|
|
|
@ -1,139 +0,0 @@
|
||||||
#
|
|
||||||
# Ethereum P2P
|
|
||||||
# (c) Copyright 2018
|
|
||||||
# Status Research & Development GmbH
|
|
||||||
#
|
|
||||||
# See the file "LICENSE", included in this
|
|
||||||
# distribution, for details about the copyright.
|
|
||||||
#
|
|
||||||
|
|
||||||
import unittest
|
|
||||||
import ethp2p/ecc
|
|
||||||
import nimcrypto/hash, nimcrypto/keccak, nimcrypto/utils
|
|
||||||
|
|
||||||
proc compare(x: openarray[byte], y: openarray[byte]): bool =
|
|
||||||
result = len(x) == len(y)
|
|
||||||
if result:
|
|
||||||
for i in 0..(len(x) - 1):
|
|
||||||
if x[i] != y[i]:
|
|
||||||
result = false
|
|
||||||
break
|
|
||||||
|
|
||||||
suite "ECC/ECDSA/ECDHE tests suite":
|
|
||||||
test "ECDHE/py-evm test_ecies.py#L19":
|
|
||||||
# ECDHE test vectors
|
|
||||||
# Copied from
|
|
||||||
# https://github.com/ethereum/py-evm/blob/master/tests/p2p/test_ecies.py#L19
|
|
||||||
const privateKeys = [
|
|
||||||
"332143e9629eedff7d142d741f896258f5a1bfab54dab2121d3ec5000093d74b",
|
|
||||||
"7ebbc6a8358bc76dd73ebc557056702c8cfc34e5cfcd90eb83af0347575fd2ad"
|
|
||||||
]
|
|
||||||
const publicKeys = [
|
|
||||||
"""f0d2b97981bd0d415a843b5dfe8ab77a30300daab3658c578f2340308a2da1a07
|
|
||||||
f0821367332598b6aa4e180a41e92f4ebbae3518da847f0b1c0bbfe20bcf4e1""",
|
|
||||||
"""83ede0f19c3c98649265956a4193677b14c338a22de2086a08d84e4446fe37e4e
|
|
||||||
233478259ec90dbeef52f4f6c890f8c38660ec7b61b9d439b8a6d1c323dc025"""
|
|
||||||
]
|
|
||||||
const sharedSecrets = [
|
|
||||||
"ee1418607c2fcfb57fda40380e885a707f49000a5dda056d828b7d9bd1f29a08",
|
|
||||||
"167ccc13ac5e8a26b131c3446030c60fbfac6aa8e31149d0869f93626a4cdf62"
|
|
||||||
]
|
|
||||||
var secret: array[KeyLength, byte]
|
|
||||||
for i in 0..1:
|
|
||||||
var s = privateKeys[i].getPrivateKey()
|
|
||||||
var p = publicKeys[i].getPublicKey()
|
|
||||||
let expect = fromHex(stripSpaces(sharedSecrets[i]))
|
|
||||||
check:
|
|
||||||
ecdhAgree(s, p, secret) == Success
|
|
||||||
compare(expect, secret) == true
|
|
||||||
|
|
||||||
test "ECDHE/cpp-ethereum crypto.cpp#L394":
|
|
||||||
# ECDHE test vectors
|
|
||||||
# Copied from https://github.com/ethereum/cpp-ethereum/blob/develop/test/unittests/libdevcrypto/crypto.cpp#L394
|
|
||||||
var expectm = """
|
|
||||||
8ac7e464348b85d9fdfc0a81f2fdc0bbbb8ee5fb3840de6ed60ad9372e718977"""
|
|
||||||
var secret: array[KeyLength, byte]
|
|
||||||
var s = keccak256.digest("ecdhAgree").data
|
|
||||||
var p = s.getPublicKey()
|
|
||||||
let expect = fromHex(stripSpaces(expectm))
|
|
||||||
check:
|
|
||||||
ecdhAgree(s, p, secret) == Success
|
|
||||||
compare(expect, secret) == true
|
|
||||||
|
|
||||||
test "ECDHE/cpp-ethereum rlpx.cpp#L425":
|
|
||||||
# ECDHE test vectors
|
|
||||||
# Copied from https://github.com/ethereum/cpp-ethereum/blob/2409d7ec7d34d5ff5770463b87eb87f758e621fe/test/unittests/libp2p/rlpx.cpp#L425
|
|
||||||
var s0 = """
|
|
||||||
332143e9629eedff7d142d741f896258f5a1bfab54dab2121d3ec5000093d74b"""
|
|
||||||
var p0 = """
|
|
||||||
f0d2b97981bd0d415a843b5dfe8ab77a30300daab3658c578f2340308a2da1a0
|
|
||||||
7f0821367332598b6aa4e180a41e92f4ebbae3518da847f0b1c0bbfe20bcf4e1"""
|
|
||||||
var e0 = """
|
|
||||||
ee1418607c2fcfb57fda40380e885a707f49000a5dda056d828b7d9bd1f29a08"""
|
|
||||||
var secret: array[KeyLength, byte]
|
|
||||||
var s = getPrivateKey(s0)
|
|
||||||
var p = getPublicKey(p0)
|
|
||||||
let expect = fromHex(stripSpaces(e0))
|
|
||||||
check:
|
|
||||||
ecdhAgree(s, p, secret) == Success
|
|
||||||
compare(expect, secret) == true
|
|
||||||
|
|
||||||
test "ECDSA/cpp-ethereum crypto.cpp#L132":
|
|
||||||
# ECDSA test vectors
|
|
||||||
# Copied from https://github.com/ethereum/cpp-ethereum/blob/develop/test/unittests/libdevcrypto/crypto.cpp#L132
|
|
||||||
var signature = """
|
|
||||||
b826808a8c41e00b7c5d71f211f005a84a7b97949d5e765831e1da4e34c9b8295d
|
|
||||||
2a622eee50f25af78241c1cb7cfff11bcf2a13fe65dee1e3b86fd79a4e3ed000"""
|
|
||||||
var pubkey = """
|
|
||||||
e40930c838d6cca526795596e368d16083f0672f4ab61788277abfa23c3740e1cc
|
|
||||||
84453b0b24f49086feba0bd978bb4446bae8dff1e79fcc1e9cf482ec2d07c3"""
|
|
||||||
var check1 = fromHex(stripSpaces(signature))
|
|
||||||
var check2 = fromHex(stripSpaces(pubkey))
|
|
||||||
var sig: Signature
|
|
||||||
var key: PublicKey
|
|
||||||
var s = keccak256.digest("sec").data
|
|
||||||
var m = keccak256.digest("msg").data
|
|
||||||
check signMessage(s, m, sig) == Success
|
|
||||||
var sersig = sig.getRaw().data
|
|
||||||
check recoverSignatureKey(sersig, m, key) == Success
|
|
||||||
var serkey = key.getRaw().data
|
|
||||||
check:
|
|
||||||
compare(sersig, check1) == true
|
|
||||||
compare(serkey, check2) == true
|
|
||||||
|
|
||||||
test "ECDSA/100 signatures":
|
|
||||||
# signature test
|
|
||||||
var rkey: PublicKey
|
|
||||||
var sig: Signature
|
|
||||||
for i in 1..100:
|
|
||||||
var m = newPrivateKey()
|
|
||||||
var s = newPrivateKey()
|
|
||||||
var key = s.getPublicKey()
|
|
||||||
check signMessage(s, m, sig) == Success
|
|
||||||
var sersig = sig.getRaw().data
|
|
||||||
check:
|
|
||||||
recoverSignatureKey(sersig, m, rkey) == Success
|
|
||||||
key == rkey
|
|
||||||
|
|
||||||
test "KEYS/100 create/recovery keys":
|
|
||||||
# key create/recovery test
|
|
||||||
var rkey: PublicKey
|
|
||||||
for i in 1..100:
|
|
||||||
var s = newPrivateKey()
|
|
||||||
var key = s.getPublicKey()
|
|
||||||
check:
|
|
||||||
recoverPublicKey(key.getRaw().data, rkey) == Success
|
|
||||||
key == rkey
|
|
||||||
|
|
||||||
test "ECDHE/100 shared secrets":
|
|
||||||
# ECDHE shared secret test
|
|
||||||
var secret1, secret2: SharedSecret
|
|
||||||
for i in 1..100:
|
|
||||||
var aliceSecret = newPrivateKey()
|
|
||||||
var alicePublic = aliceSecret.getPublicKey()
|
|
||||||
var bobSecret = newPrivateKey()
|
|
||||||
var bobPublic = bobSecret.getPublicKey()
|
|
||||||
check:
|
|
||||||
ecdhAgree(aliceSecret, bobPublic, secret1) == Success
|
|
||||||
ecdhAgree(bobSecret, alicePublic, secret2) == Success
|
|
||||||
secret1 == secret2
|
|
|
@ -8,7 +8,7 @@
|
||||||
#
|
#
|
||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
import ethp2p/ecc, ethp2p/ecies
|
import eth_keys, ethp2p/ecies
|
||||||
import nimcrypto/utils, nimcrypto/sha2, nimcrypto/hmac, nimcrypto/rijndael
|
import nimcrypto/utils, nimcrypto/sha2, nimcrypto/hmac, nimcrypto/rijndael
|
||||||
|
|
||||||
proc compare[A, B](x: openarray[A], y: openarray[B], s: int = 0): bool =
|
proc compare[A, B](x: openarray[A], y: openarray[B], s: int = 0): bool =
|
||||||
|
@ -123,7 +123,7 @@ suite "ECIES test suite":
|
||||||
]
|
]
|
||||||
var data: array[1024, byte]
|
var data: array[1024, byte]
|
||||||
for i in 0..1:
|
for i in 0..1:
|
||||||
var s = secretKeys[i].getPrivateKey()
|
var s = initPrivateKey(secretKeys[i])
|
||||||
var cipher = fromHex(stripSpaces(cipherText[i]))
|
var cipher = fromHex(stripSpaces(cipherText[i]))
|
||||||
var expect = fromHex(stripSpaces(expectText[i]))
|
var expect = fromHex(stripSpaces(expectText[i]))
|
||||||
check:
|
check:
|
||||||
|
@ -164,7 +164,7 @@ suite "ECIES test suite":
|
||||||
]
|
]
|
||||||
var data: array[1024, byte]
|
var data: array[1024, byte]
|
||||||
for i in 0..3:
|
for i in 0..3:
|
||||||
var s = secretKeys[i].getPrivateKey()
|
var s = initPrivateKey(secretKeys[i])
|
||||||
var cipher = fromHex(stripSpaces(cipherData[i]))
|
var cipher = fromHex(stripSpaces(cipherData[i]))
|
||||||
check:
|
check:
|
||||||
eciesDecrypt(cipher, data, s) == EciesStatus.Success
|
eciesDecrypt(cipher, data, s) == EciesStatus.Success
|
||||||
|
|
Loading…
Reference in New Issue