mirror of
https://github.com/logos-messaging/nim-chat-poc.git
synced 2026-01-02 14:13:10 +00:00
Add ECDH functions
This commit is contained in:
parent
9a455cc4d2
commit
d0046eabf3
43
src/crypto/ecdh.nim
Normal file
43
src/crypto/ecdh.nim
Normal file
@ -0,0 +1,43 @@
|
||||
import results
|
||||
import libp2p/crypto/curve25519
|
||||
import bearssl/rand
|
||||
|
||||
type PrivateKey* = object
|
||||
bytes: Curve25519Key
|
||||
|
||||
type PublicKey* = object
|
||||
bytes: Curve25519Key
|
||||
|
||||
|
||||
proc bytes*(key: PrivateKey): Curve25519Key =
|
||||
return key.bytes
|
||||
|
||||
proc bytes*(key: PublicKey): Curve25519Key =
|
||||
return key.bytes
|
||||
|
||||
proc createRandomKey*(): Result[PrivateKey, string] =
|
||||
let rng = HmacDrbgContext.new()
|
||||
if rng.isNil:
|
||||
return err("Failed to create HmacDrbgContext with system randomness")
|
||||
ok(PrivateKey(bytes: Curve25519Key.random(rng[])))
|
||||
|
||||
proc loadKeyFromBytes*(bytes: openArray[byte]): Result[PrivateKey, string] =
|
||||
if bytes.len != Curve25519KeySize:
|
||||
return err("Private key size must be 32 bytes")
|
||||
ok(PrivateKey(bytes: intoCurve25519Key(bytes)))
|
||||
|
||||
|
||||
proc getPublicKey*(privateKey: PrivateKey): PublicKey =
|
||||
PublicKey(bytes: public(privateKey.bytes))
|
||||
|
||||
|
||||
proc Dh*(privateKey: PrivateKey, publicKey: PublicKey): Result[seq[
|
||||
byte], string] =
|
||||
|
||||
var outputKey = publicKey.bytes
|
||||
try:
|
||||
Curve25519.mul(outputKey, privateKey.bytes)
|
||||
except CatchableError as e:
|
||||
return err("Failed to compute shared secret: " & e.msg)
|
||||
|
||||
return ok(outputKey.getBytes())
|
||||
@ -2,6 +2,7 @@ import waku/waku_core
|
||||
import std/[random, times]
|
||||
import crypto
|
||||
import blake2
|
||||
import strutils
|
||||
|
||||
proc getTimestamp*(): Timestamp =
|
||||
result = waku_core.getNanosecondTime(getTime().toUnix())
|
||||
@ -21,4 +22,9 @@ proc get_addr*(pubkey: SkPublicKey): string =
|
||||
result = hash_func(pubkey.toHexCompressed())
|
||||
|
||||
|
||||
|
||||
proc bytesToHex*(bytes: openarray[byte], lowercase: bool = false): string =
|
||||
## Convert bytes to hex string with case option
|
||||
result = ""
|
||||
for b in bytes:
|
||||
let hex = b.toHex(2)
|
||||
result.add(if lowercase: hex.toLower() else: hex)
|
||||
|
||||
0
tests/config.nims
Normal file
0
tests/config.nims
Normal file
66
tests/test_curve25519.nim
Normal file
66
tests/test_curve25519.nim
Normal file
@ -0,0 +1,66 @@
|
||||
# test_example.nim
|
||||
import unittest
|
||||
import ../src/crypto/ecdh # TODO use config.nims
|
||||
import results
|
||||
import ../src/utils
|
||||
|
||||
# Key share test from RFC-7748:
|
||||
const ks7748_a_priv = "77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a"
|
||||
const ks7748_a_pub = "8520f0098930a754748b7ddcb43ef75a0dbf3a0d26381af4eba4a98eaa9b4e6a" # Public key point (x co-ord)
|
||||
|
||||
const ks7748_b_priv = "5dab087e624a8a4b79e17f8b83800ee66f3bb1292618b6fd1c2f8b27ff88e0eb"
|
||||
const ks7748_b_pub = "de9edb7d7b7dc1b4d35b61c2ece435373f8343c85b78674dadfc7e146f882b4f" # Public key point (x co-ord)s
|
||||
|
||||
const ks7748_shared_key = "4a5d9d5ba4ce2de1728e3bf480350f25e07e21c947d19e3376f09b3c1e161742"
|
||||
|
||||
import parseutils
|
||||
|
||||
proc hexToArray*[N: static[int]](hexStr: string): array[N, byte] =
|
||||
## Converts hex string to fixed-size byte array
|
||||
if hexStr.len != N * 2:
|
||||
raise newException(ValueError,
|
||||
"Hex string length (" & $hexStr.len & ") doesn't match array size (" & $(
|
||||
N*2) & ")")
|
||||
|
||||
for i in 0..<N:
|
||||
if parseHex(hexStr[i*2..i*2+1], result[i]) == 0:
|
||||
raise newException(ValueError, "Invalid hex pair: " & hexStr[i*2..i*2+1])
|
||||
|
||||
# Usage
|
||||
|
||||
suite "X25519":
|
||||
test "Key Loading":
|
||||
|
||||
let a_priv = loadKeyFromBytes(hexToArray[32](ks7748_a_priv)).get()
|
||||
let a_pub = a_priv.getPublicKey()
|
||||
|
||||
check bytesToHex(a_pub.bytes, lowercase = true) == ks7748_a_pub
|
||||
check bytesToHex(a_pub.bytes, lowercase = true) != ks7748_b_pub
|
||||
|
||||
let b_priv = loadKeyFromBytes(hexToArray[32](ks7748_b_priv)).get()
|
||||
let b_pub = b_priv.getPublicKey()
|
||||
|
||||
check bytesToHex(b_pub.bytes, lowercase = true) != ks7748_a_pub
|
||||
check bytesToHex(b_pub.bytes, lowercase = true) == ks7748_b_pub
|
||||
|
||||
test "ECDH":
|
||||
|
||||
let a_priv = loadKeyFromBytes(hexToArray[32](ks7748_a_priv)).get()
|
||||
let a_pub = a_priv.getPublicKey()
|
||||
|
||||
let b_priv = loadKeyFromBytes(hexToArray[32](ks7748_b_priv)).get()
|
||||
let b_pub = b_priv.getPublicKey()
|
||||
|
||||
|
||||
let sk1 = Dh(a_priv, b_pub)
|
||||
if sk1.isErr:
|
||||
raise newException(ValueError, "ECDH1 failed: " & sk1.error)
|
||||
|
||||
let sk2 = Dh(b_priv, a_pub)
|
||||
if sk2.isErr:
|
||||
raise newException(ValueError, "ECDH2 failed: " & sk2.error)
|
||||
|
||||
check bytesToHex(sk1.get(), lowercase = true) == ks7748_shared_key
|
||||
check bytesToHex(sk2.get(), lowercase = true) == ks7748_shared_key
|
||||
|
||||
# Run with: nim c -r test_example.nim
|
||||
Loading…
x
Reference in New Issue
Block a user