Skip to content

Commit

Permalink
feat: introduce Nim impl of generateAlias
Browse files Browse the repository at this point in the history
Closes #32
  • Loading branch information
michaelsbradleyjr committed Aug 18, 2020
1 parent 6f39981 commit e4ef049
Show file tree
Hide file tree
Showing 23 changed files with 3,378 additions and 60 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
.vscode
bin/
/bottles/
/DLLs/
build/
vendor/.nimble
tmp
Expand Down
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,6 @@
[submodule "vendor/nim-json-serialization"]
path = vendor/nim-json-serialization
url = https://github.com/status-im/nim-json-serialization.git
[submodule "vendor/nim-secp256k1"]
path = vendor/nim-secp256k1
url = https://github.com/status-im/nim-secp256k1.git
135 changes: 106 additions & 29 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ BUILD_SYSTEM_DIR := vendor/nimbus-build-system
nim_status \
status-go \
test \
test-shims-c \
test-login-c \
test-c-shims \
test-c-login \
tests \
tests-c \
tests-nim \
Expand Down Expand Up @@ -67,8 +67,12 @@ ifeq ($(detected_OS),Darwin)
export CGO_CFLAGS
CFLAGS := -mmacosx-version-min=10.13
export CFLAGS
LIBSTATUS_EXT := dylib
else ifeq ($(detected_OS),Windows)
LIBSTATUS_EXT := dll
else
BOTTLES_TARGET := bottles-dummy
LIBSTATUS_EXT := so
endif

bottles: $(BOTTLES_TARGET)
Expand Down Expand Up @@ -98,72 +102,144 @@ $(BOTTLE_PCRE):
bottles-macos: | $(BOTTLE_OPENSSL) $(BOTTLE_PCRE)
rm -rf bottles/Downloads

deps: | deps-common bottles
ifeq ($(detected_OS),Darwin)
NIM_DEP_LIBS := bottles/openssl/lib/libcrypto.a \
bottles/openssl/lib/libssl.a \
bottles/pcre/lib/libpcre.a
else ifeq ($(detected_OS),Linux)
NIM_DEP_LIBS := -lcrypto -lssl -lpcre
endif

NIM_WINDOWS_PREBUILT_DLLS ?= DLLs/pcre.dll
NIM_WINDOWS_PREBUILT_DLLDIR := $(shell pwd)/$(shell dirname "$(NIM_WINDOWS_PREBUILT_DLLS)")

$(NIM_WINDOWS_PREBUILT_DLLS):
ifeq ($(detected_OS),Windows)
echo -e "\e[92mFetching:\e[39m prebuilt DLLs from nim-lang.org"
rm -rf DLLs
mkdir -p DLLs
cd DLLs && \
wget https://nim-lang.org/download/dlls.zip && \
unzip dlls.zip
endif

deps: | deps-common bottles $(NIM_WINDOWS_PREBUILT_DLLS)

update: | update-common

ifeq ($(detected_OS),Darwin)
NIM_PARAMS := $(NIM_PARAMS) -L:"-framework Foundation -framework Security -framework IOKit -framework CoreServices"
FRAMEWORKS := -framework CoreFoundation -framework CoreServices -framework IOKit -framework Security
NIM_PARAMS := $(NIM_PARAMS) -L:"$(FRAMEWORKS)"
endif

# TODO: control debug/release builds with a Make var
# We need `-d:debug` to get Nim's default stack traces.
NIM_PARAMS += -d:debug

STATUSGO := vendor/status-go/build/bin/libstatus.a
STATUSGO := vendor/status-go/build/bin/libstatus.$(LIBSTATUS_EXT)
STATUSGO_LIBDIR := $(shell pwd)/$(shell dirname "$(STATUSGO)")
export STATUSGO_LIBDIR

status-go: $(STATUSGO)
$(STATUSGO): | deps
echo -e $(BUILD_MSG) "status-go"
+ cd vendor/status-go && \
$(MAKE) statusgo-library $(HANDLE_OUTPUT)
$(MAKE) statusgo-shared-library $(HANDLE_OUTPUT)

NIMSTATUS := build/nim_status.a

nim_status: | $(NIMSTATUS)
$(NIMSTATUS): | deps
echo -e $(BUILD_MSG) "$@" && \
$(ENV_SCRIPT) nim c $(NIM_PARAMS) --app:staticLib --header --noMain --nimcache:nimcache/nim_status -o:$@ src/nim_status/c/nim_status.nim
cp nimcache/nim_status/nim_status.h build/nim_status.h
mv nim_status.a build/
$(ENV_SCRIPT) nim c \
$(NIM_PARAMS) \
--app:staticLib \
--header \
--noMain \
-o:$@ \
src/nim_status/c/nim_status.nim
cp nimcache/debug/nim_status/nim_status.h build/nim_status.h
mv nim_status.a build/

SHIMS := tests/c/build/shims.a

shims: | $(SHIMS)
$(SHIMS): | deps
echo -e $(BUILD_MSG) "$@" && \
$(ENV_SCRIPT) nim c $(NIM_PARAMS) --app:staticLib --header --noMain --nimcache:nimcache/nim_status -o:$@ tests/c/shims.nim
cp nimcache/nim_status/shims.h tests/c/build/shims.h
$(ENV_SCRIPT) nim c \
$(NIM_PARAMS) \
--app:staticLib \
--header \
--noMain \
-o:$@ \
tests/c/shims.nim
cp nimcache/debug/shims/shims.h tests/c/build/shims.h
mv shims.a tests/c/build/

test-shims-c: | $(STATUSGO) clean-data-dirs create-data-dirs $(SHIMS)
test-c-template: | $(STATUSGO) clean-data-dirs create-data-dirs
mkdir -p tests/c/build
echo "Compiling 'tests/c/shims'"
echo "Compiling 'tests/c/$(TEST_NAME)'"
$(ENV_SCRIPT) $(CC) \
$(TEST_INCLUDES) \
-I"$(CURDIR)/vendor/nimbus-build-system/vendor/Nim/lib" \
tests/c/$(TEST_NAME).c \
$(TEST_DEPS) \
$(NIM_DEP_LIBS) \
-L$(STATUSGO_LIBDIR) \
-lstatus \
$(FRAMEWORKS) \
-lm \
-pthread \
-o tests/c/build/$(TEST_NAME)
[[ $(detected_OS) = Darwin ]] && \
install_name_tool -add_rpath \
"$(STATUSGO_LIBDIR)" \
tests/c/build/$(TEST_NAME) && \
install_name_tool -change \
libstatus.dylib \
@rpath/libstatus.dylib \
tests/c/build/$(TEST_NAME) || true
echo "Executing 'tests/c/build/$(TEST_NAME)'"
ifeq ($(detected_OS),Darwin)
$(ENV_SCRIPT) $(CC) -I"$(CURDIR)/tests/c/build" -I"$(CURDIR)/vendor/nimbus-build-system/vendor/Nim/lib" tests/c/shims.c $(SHIMS) $(STATUSGO) -framework CoreFoundation -framework CoreServices -framework IOKit -framework Security -lm -pthread -o tests/c/build/shims
./tests/c/build/$(TEST_NAME)
else ifeq ($(detected_OS),Windows)
PATH="$(STATUSGO_LIBDIR)":"$(NIM_WINDOWS_PREBUILT_DLLDIR)":/usr/bin:/bin:"$(PATH)" \
./tests/c/build/$(TEST_NAME)
else
$(ENV_SCRIPT) $(CC) -I"$(CURDIR)/tests/c/build" -I"$(CURDIR)/vendor/nimbus-build-system/vendor/Nim/lib" tests/c/shims.c $(SHIMS) $(STATUSGO) -lm -pthread -o tests/c/build/shims
LD_LIBRARY_PATH="$(STATUSGO_LIBDIR)" \
./tests/c/build/$(TEST_NAME)
endif
echo "Executing 'tests/c/build/shims'"
$(ENV_SCRIPT) ./tests/c/build/shims

test-login-c: | $(STATUSGO) clean-data-dirs create-data-dirs $(NIMSTATUS)
mkdir -p tests/c/build
echo "Compiling 'tests/c/login'"
ifeq ($(detected_OS),Darwin)
$(ENV_SCRIPT) $(CC) -I"$(CURDIR)/build" -I"$(CURDIR)/vendor/nimbus-build-system/vendor/Nim/lib" tests/c/login.c $(NIMSTATUS) $(STATUSGO) -framework CoreFoundation -framework CoreServices -framework IOKit -framework Security -lm -pthread -o tests/c/build/login
else
$(ENV_SCRIPT) $(CC) -I"$(CURDIR)/build" -I"$(CURDIR)/vendor/nimbus-build-system/vendor/Nim/lib" tests/c/login.c $(NIMSTATUS) $(STATUSGO) -lm -pthread -o tests/c/build/login
endif
echo "Executing 'tests/c/build/login'"
$(ENV_SCRIPT) ./tests/c/build/login
SHIMS_INCLUDES := -I\"$(CURDIR)/tests/c/build\"

test-c-shims: | $(SHIMS)
$(MAKE) TEST_DEPS=$(SHIMS) \
TEST_INCLUDES=$(SHIMS_INCLUDES) \
TEST_NAME=shims \
test-c-template

LOGIN_INCLUDES := -I\"$(CURDIR)/build\"

test-c-login: | $(NIMSTATUS)
$(MAKE) TEST_DEPS=$(NIMSTATUS) \
TEST_INCLUDES=$(LOGIN_INCLUDES) \
TEST_NAME=login \
test-c-template

tests-c:
$(MAKE) test-shims-c
$(MAKE) test-login-c
$(MAKE) test-c-shims
$(MAKE) test-c-login

tests-nim: | $(STATUSGO)
ifeq ($(detected_OS),Darwin)
$(ENV_SCRIPT) nimble test
else ifeq ($(detected_OS),Windows)
PATH="$(STATUSGO_LIBDIR)":"$(NIM_WINDOWS_PREBUILT_DLLDIR)":/usr/bin:/bin:"$(PATH)" \
$(ENV_SCRIPT) nimble test
else
LD_LIBRARY_PATH="$(STATUSGO_LIBDIR)" \
$(ENV_SCRIPT) nimble test
endif

tests: tests-nim tests-c

Expand All @@ -172,6 +248,7 @@ test: tests
clean: | clean-common clean-build-dirs clean-data-dirs
rm -rf $(STATUSGO)
rm -rf bottles
rm -rf DLLs

clean-build-dirs:
rm -rf build/*
Expand Down
8 changes: 0 additions & 8 deletions config.nims
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,6 @@ if defined(macosx):
--dynliboverrideall # don't use dlopen()
--tlsEmulation:off
switch("passL", "-lstdc++")
# statically linke these libs
switch("passL", "bottles/openssl/lib/libcrypto.a")
switch("passL", "bottles/openssl/lib/libssl.a")
switch("passL", "bottles/pcre/lib/libpcre.a")
# https://code.videolan.org/videolan/VLCKit/-/issues/232
switch("passL", "-Wl,-no_compact_unwind")
# set the minimum supported macOS version to 10.13
Expand All @@ -25,9 +21,6 @@ elif defined(windows):
switch("passL", "-Wl,-as-needed")
else:
--dynliboverrideall # don't use dlopen()
# dynamically link these libs, since we're opting out of dlopen()
switch("passL", "-lcrypto")
switch("passL", "-lssl")
# don't link libraries we're not actually using
switch("passL", "-Wl,-as-needed")

Expand All @@ -39,4 +32,3 @@ switch("warning", "ObservableStores:off")

# Too many false positives for "Warning: method has lock level <unknown>, but another method has 0 [LockLevel]"
switch("warning", "LockLevel:off")

7 changes: 6 additions & 1 deletion nim_status.nimble
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,12 @@ proc buildAndRunBinary(name: string, srcDir = "./", params = "", cmdParams = "",
var extra_params = params
for i in 2..<paramCount():
extra_params &= " " & paramStr(i)
exec "nim " & lang & " --out:./tests/nim/build/" & name & " -r " & extra_params & " " & srcDir & name & ".nim" & " " & cmdParams
exec "nim " & lang & " --out:./tests/nim/build/" & name & " " & extra_params & " " & srcDir & name & ".nim" & " " & cmdParams
if defined(macosx):
exec "install_name_tool -add_rpath " & getEnv("STATUSGO_LIBDIR") & " tests/nim/build/" & name
exec "install_name_tool -change libstatus.dylib @rpath/libstatus.dylib tests/nim/build/" & name
echo "Executing 'tests/nim/build/" & name & "'"
exec "tests/nim/build/" & name

### Tasks
task test, "Run all tests":
Expand Down
4 changes: 2 additions & 2 deletions src/nim_status.nim
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ from nim_status/types import
SignalCallback

from nim_status/lib/shim as nim_shim import
hashMessage
hashMessage,
generateAlias

from nim_status/go/shim as go_shim import
initKeystore,
Expand All @@ -18,7 +19,6 @@ from nim_status/go/shim as go_shim import
addPeer,
setSignalEventCallback,
sendTransaction,
generateAlias,
identicon,
login,
logout,
Expand Down
3 changes: 3 additions & 0 deletions src/nim_status/c/lib.nim
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import ../lib
import lib/shim as nim_shim_c
import sys

proc hashMessage*(message: cstring): cstring =
let hash = lib.hashMessage($message)
result = cast[cstring](c_malloc(csize_t hash.len + 1))
copyMem(result, hash.cstring, hash.len)
result[hash.len] = '\0'

let generateAlias* = nim_shim_c.generateAlias
6 changes: 6 additions & 0 deletions src/nim_status/c/lib/shim.nim
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,9 @@ proc hashMessage*(message: cstring): cstring =
result = cast[cstring](c_malloc(csize_t hash.len + 1))
copyMem(result, hash.cstring, hash.len)
result[hash.len] = '\0'

proc generateAlias*(pubKey: cstring): cstring =
let alias = nim_shim.generateAlias($pubKey)
result = cast[cstring](c_malloc(csize_t alias.len + 1))
copyMem(result, alias.cstring, alias.len)
result[alias.len] = '\0'
2 changes: 1 addition & 1 deletion src/nim_status/c/nim_status.nim
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import lib/shim as nim_shim

let hashMessage {.exportc.} = nim_shim.hashMessage
let generateAlias {.exportc.} = nim_shim.generateAlias

import go/shim as go_shim

Expand All @@ -16,7 +17,6 @@ let callRPC {.exportc.} = go_shim.callRPC
let callPrivateRPC {.exportc.} = go_shim.callPrivateRPC
let addPeer {.exportc.} = go_shim.addPeer
let sendTransaction {.exportc.} = go_shim.sendTransaction
let generateAlias {.exportc.} = go_shim.generateAlias
let identicon {.exportc.} = go_shim.identicon
let login {.exportc.} = go_shim.login
let logout {.exportc.} = go_shim.logout
Expand Down
20 changes: 19 additions & 1 deletion src/nim_status/lib.nim
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
import lib/alias
import lib/alias/data
import lib/util
import nimcrypto
import strformat
import strutils
import unicode

const END_OF_MEDIUM = Rune(0x19).toUTF8
const prefix = END_OF_MEDIUM & "Ethereum Signed Message:\n"

proc hashMessage*(message: string): string =
## hashMessage calculates the hash of a message to be safely signed by the keycard
## hashMessage calculates the hash of a message to be safely signed by the keycard.
## The hash is calulcated as
## keccak256("\x19Ethereum Signed Message:\n"${message length}${message}).
## This gives context to the signed message and prevents signing of transactions.
Expand All @@ -18,3 +21,18 @@ proc hashMessage*(message: string): string =
except:
discard
"0x" & toLower($keccak_256.digest(prefix & $(msg.len) & msg))

proc generateAlias*(pubKey: string): string =
## generateAlias returns a 3-words generated name given a hex encoded (prefixed with 0x) public key.
## We ignore any error, empty string is considered an error.
result = ""
if isPubKey(pubKey):
try:
let seed = truncPubKey(pubKey)
let generator = Lsfr(poly: poly, data: seed)
let adjective1 = adjectives[generator.next mod adjectives.len.uint64]
let adjective2 = adjectives[generator.next mod adjectives.len.uint64]
let animal = animals[generator.next mod animals.len.uint64]
result = fmt("{adjective1} {adjective2} {animal}")
except:
discard
25 changes: 25 additions & 0 deletions src/nim_status/lib/alias.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
from bitops import bitand, bitor, bitxor
import secp256k1
import stew/endians2

# For details: https://en.wikipedia.org/wiki/Linear-feedback_shift_register
type Lsfr* = ref object
poly*: uint64
data*: uint64

proc next*(self: Lsfr): uint64 =
const one: uint64 = 1
const limit: uint64 = 64
var bit: uint64 = 0
var i: uint64 = 0
while i < limit:
if bitand(self.poly, one shl i) != 0:
bit = bitxor(bit, self.data shr i)
i += one
bit = bitand(bit, one)
self.data = bitor(self.data shl one, bit)
result = self.data

proc truncPubKey*(pubKey: string): uint64 =
let rawKey = SkPublicKey.fromHex(pubKey).get.toRaw
fromBytesBE(uint64, rawKey[25..32])
Loading

0 comments on commit e4ef049

Please sign in to comment.