Skip to content

Commit

Permalink
nvm: add crypto methods
Browse files Browse the repository at this point in the history
  • Loading branch information
bibibong committed Jun 6, 2018
1 parent b4431a7 commit f85a91f
Show file tree
Hide file tree
Showing 12 changed files with 218 additions and 7 deletions.
32 changes: 32 additions & 0 deletions crypto/hash/hash.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,18 @@ package hash

import (
"crypto/sha256"
"encoding/base64"

keccak "github.com/nebulasio/go-nebulas/crypto/sha3"
"golang.org/x/crypto/ripemd160"
"golang.org/x/crypto/sha3"
)

// const alphabet = "./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"

var bcEncoding = base64.NewEncoding(alphabet)

// Sha256 returns the SHA-256 digest of the data.
func Sha256(args ...[]byte) []byte {
hasher := sha256.New()
Expand Down Expand Up @@ -61,3 +67,29 @@ func Ripemd160(args ...[]byte) []byte {
}
return hasher.Sum(nil)
}

// Base64Encode encode to base64
func Base64Encode(src []byte) []byte {
n := bcEncoding.EncodedLen(len(src))
dst := make([]byte, n)
bcEncoding.Encode(dst, src)
// for dst[n-1] == '=' {
// n--
// }
return dst[:n]
}

// Base64Decode decode base64
func Base64Decode(src []byte) ([]byte, error) {
numOfEquals := 4 - (len(src) % 4)
for i := 0; i < numOfEquals; i++ {
src = append(src, '=')
}

dst := make([]byte, bcEncoding.DecodedLen(len(src)))
n, err := bcEncoding.Decode(dst, src)
if err != nil {
return nil, err
}
return dst[:n], nil
}
41 changes: 39 additions & 2 deletions nebtestkit/cases/contract/contract.lib.crypto.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -382,8 +382,7 @@ var caseGroup = {
status: 1,
result: "\"n1F8QbdnhqpPXDPFT2c9a581tpia8iuF7o2\""
}
}
,
},
{
"name": "0-5. test recoverAddress invalid alg",
"testInput": {
Expand All @@ -402,6 +401,44 @@ var caseGroup = {
status: 1,
result: "null"
}
},
{
"name": "0-6. test md5",
"testInput": {
value: "0",
nonce: 1,
gasPrice: 1000000,
gasLimit: 2000000,
contract: {
function: "testMd5",
args: "[\"Nebulas is a next generation public blockchain, aiming for a continuously improving ecosystem.\"]"
}
},
"testExpect": {
canExcuteTx: true,
toBalanceChange: "0",
status: 1,
result: "\"9954125a33a380c3117269cff93f76a7\""
}
},
{
"name": "0-7. test base64",
"testInput": {
value: "0",
nonce: 1,
gasPrice: 1000000,
gasLimit: 2000000,
contract: {
function: "testBase64",
args: "[\"https://y.qq.com/portal/player_radio.html#id=99\"]"
}
},
"testExpect": {
canExcuteTx: true,
toBalanceChange: "0",
status: 1,
result: "\"aHR0cHM6Ly95LnFxLmNvbS9wb3J0YWwvcGxheWVyX3JhZGlvLmh0bWwjaWQ9OTk=\""
}
}
]
};
Expand Down
8 changes: 8 additions & 0 deletions nf/nvm/cfuncs.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ char *Sha256Func(const char *data, size_t *gasCnt);
char *Sha3256Func(const char *data, size_t *gasCnt);
char *Ripemd160Func(const char *data, size_t *gasCnt);
char *RecoverAddressFunc(int alg, const char *data, const char *sign, size_t *gasCnt);
char *Md5Func(const char *data, size_t *gasCnt);
char *Base64Func(const char *data, size_t *gasCnt);
// The gateway functions.
void V8Log_cgo(int level, const char *msg) {
Expand Down Expand Up @@ -100,6 +102,12 @@ char *Ripemd160Func_cgo(const char *data, size_t *gasCnt) {
char *RecoverAddressFunc_cgo(int alg, const char *data, const char *sign, size_t *gasCnt) {
return RecoverAddressFunc(alg, data, sign, gasCnt);
}
char *Md5Func_cgo(const char *data, size_t *gasCnt) {
return Md5Func(data, gasCnt);
}
char *Base64Func_cgo(const char *data, size_t *gasCnt) {
return Base64Func(data, gasCnt);
}
*/
import "C"
22 changes: 22 additions & 0 deletions nf/nvm/crypto.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ package nvm
import "C"

import (
"crypto/md5"

"github.com/nebulasio/go-nebulas/core"
"github.com/nebulasio/go-nebulas/crypto/hash"
"github.com/nebulasio/go-nebulas/crypto/keystore"
Expand Down Expand Up @@ -100,3 +102,23 @@ func RecoverAddressFunc(alg int, data, sign *C.char, gasCnt *C.size_t) *C.char {

return C.CString(addr.String())
}

// Md5Func ..
//export Md5Func
func Md5Func(data *C.char, gasCnt *C.size_t) *C.char {
s := C.GoString(data)
*gasCnt = C.size_t(len(s) * 100)

r := md5.Sum([]byte(s))
return C.CString(byteutils.Hex(r[:]))
}

// Base64Func ..
//export Base64Func
func Base64Func(data *C.char, gasCnt *C.size_t) *C.char {
s := C.GoString(data)
*gasCnt = C.size_t(1000 + len(s))

r := hash.Base64Encode([]byte(s))
return C.CString(string(r))
}
6 changes: 5 additions & 1 deletion nf/nvm/engine_v8.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ char *Sha256Func_cgo(const char *data, size_t *gasCnt);
char *Sha3256Func_cgo(const char *data, size_t *gasCnt);
char *Ripemd160Func_cgo(const char *data, size_t *gasCnt);
char *RecoverAddressFunc_cgo(int alg, const char *data, const char *sign, size_t *gasCnt);
char *Md5Func_cgo(const char *data, size_t *gasCnt);
char *Base64Func_cgo(const char *data, size_t *gasCnt);
void EventTriggerFunc_cgo(void *handler, const char *topic, const char *data, size_t *gasCnt);
Expand Down Expand Up @@ -132,7 +134,9 @@ func InitV8Engine() {
C.InitializeCrypto((C.Sha256Func)(unsafe.Pointer(C.Sha256Func_cgo)),
(C.Sha3256Func)(unsafe.Pointer(C.Sha3256Func_cgo)),
(C.Ripemd160Func)(unsafe.Pointer(C.Ripemd160Func_cgo)),
(C.RecoverAddressFunc)(unsafe.Pointer(C.RecoverAddressFunc_cgo)))
(C.RecoverAddressFunc)(unsafe.Pointer(C.RecoverAddressFunc_cgo)),
(C.Md5Func)(unsafe.Pointer(C.Md5Func_cgo)),
(C.Base64Func)(unsafe.Pointer(C.Base64Func_cgo)))
}

// DisposeV8Engine dispose the v8 engine.
Expand Down
Binary file modified nf/nvm/native-lib/libnebulasv8.dylib
Binary file not shown.
8 changes: 8 additions & 0 deletions nf/nvm/test/contract_crypto.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,14 @@ Contract.prototype = {

testRecoverAddress: function(alg, hash, sign) {
return crypto.recoverAddress(alg, hash, sign);
},

testMd5: function(data) {
return crypto.md5(data);
},

testBase64: function(data) {
return crypto.base64(data);
}
};

Expand Down
2 changes: 2 additions & 0 deletions nf/nvm/test/test_crypto.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ eq(crypto.sha256(input), "a32d6d686968192663b9c9e21e6a3ba1ba9b2e288470c2f98b7902
eq(crypto.sha3256(input), "564733f9f3e139b925cfb1e7e50ba8581e9107b13e4213f2e4708d9c284be75b");
eq(crypto.ripemd160(input), "4236aa9974eb7b9ddb0f7a7ed06d4bf3d9c0e386");
eq(crypto.recoverAddress(1, "564733f9f3e139b925cfb1e7e50ba8581e9107b13e4213f2e4708d9c284be75b", "d80e282d165f8c05d8581133df7af3c7c41d51ec7cd8470c18b84a31b9af6a9d1da876ab28a88b0226707744679d4e180691aca6bdef5827622396751a0670c101"), "n1F8QbdnhqpPXDPFT2c9a581tpia8iuF7o2");
eq(crypto.md5(input), "9954125a33a380c3117269cff93f76a7");
eq(crypto.base64(input), "TmVidWxhcyBpcyBhIG5leHQgZ2VuZXJhdGlvbiBwdWJsaWMgYmxvY2tjaGFpbiwgYWltaW5nIGZvciBhIGNvbnRpbnVvdXNseSBpbXByb3ZpbmcgZWNvc3lzdGVtLg==");

// alg is not a safe integer
try {
Expand Down
6 changes: 5 additions & 1 deletion nf/nvm/v8/engine.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,11 +81,15 @@ typedef char *(*Sha3256Func)(const char *data, size_t *counterVal);
typedef char *(*Ripemd160Func)(const char *data, size_t *counterVal);
typedef char *(*RecoverAddressFunc)(int alg, const char *data, const char *sign,
size_t *counterVal);
typedef char *(*Md5Func)(const char *data, size_t *counterVal);
typedef char *(*Base64Func)(const char *data, size_t *counterVal);

EXPORT void InitializeCrypto(Sha256Func sha256,
Sha3256Func sha3256,
Ripemd160Func ripemd160,
RecoverAddressFunc recoverAddress);
RecoverAddressFunc recoverAddress,
Md5Func md5,
Base64Func base64);

// version
EXPORT char *GetV8Version();
Expand Down
80 changes: 77 additions & 3 deletions nf/nvm/v8/lib/crypto.cc
Original file line number Diff line number Diff line change
Expand Up @@ -24,20 +24,25 @@ static Sha256Func sSha256 = NULL;
static Sha3256Func sSha3256 = NULL;
static Ripemd160Func sRipemd160 = NULL;
static RecoverAddressFunc sRecoverAddress = NULL;
static Md5Func sMd5 = NULL;
static Base64Func sBase64 = NULL;

void InitializeCrypto(Sha256Func sha256,
Sha3256Func sha3256,
Ripemd160Func ripemd160,
RecoverAddressFunc recoverAddress) {
RecoverAddressFunc recoverAddress,
Md5Func md5,
Base64Func base64) {
sSha256 = sha256;
sSha3256 = sha3256;
sRipemd160 = ripemd160;
sRecoverAddress = recoverAddress;
sMd5 = md5;
sBase64 = base64;
}

void NewCryptoInstance(Isolate *isolate, Local<Context> context) {
Local<ObjectTemplate> cryptoTpl = ObjectTemplate::New(isolate);
// cryptoTpl->SetInternalFieldCount(1);

cryptoTpl->Set(String::NewFromUtf8(isolate, "sha256"),
FunctionTemplate::New(isolate, Sha256Callback),
Expand All @@ -58,9 +63,18 @@ void NewCryptoInstance(Isolate *isolate, Local<Context> context) {
FunctionTemplate::New(isolate, RecoverAddressCallback),
static_cast<PropertyAttribute>(PropertyAttribute::DontDelete |
PropertyAttribute::ReadOnly));

cryptoTpl->Set(String::NewFromUtf8(isolate, "md5"),
FunctionTemplate::New(isolate, Md5Callback),
static_cast<PropertyAttribute>(PropertyAttribute::DontDelete |
PropertyAttribute::ReadOnly));

cryptoTpl->Set(String::NewFromUtf8(isolate, "base64"),
FunctionTemplate::New(isolate, Base64Callback),
static_cast<PropertyAttribute>(PropertyAttribute::DontDelete |
PropertyAttribute::ReadOnly));

Local<Object> instance = cryptoTpl->NewInstance(context).ToLocalChecked();
// instance->SetInternalField(0, External::New(isolate, handler));

context->Global()->DefineOwnProperty(
context, String::NewFromUtf8(isolate, "_native_crypto"), instance,
Expand Down Expand Up @@ -203,3 +217,63 @@ void RecoverAddressCallback(const FunctionCallbackInfo<Value> &info) {
// record storage usage.
IncrCounter(isolate, isolate->GetCurrentContext(), cnt);
}

// Md5Callback
void Md5Callback(const FunctionCallbackInfo<Value> &info) {
Isolate *isolate = info.GetIsolate();

if (info.Length() != 1) {
isolate->ThrowException(String::NewFromUtf8(
isolate, "md5() requires only 1 argument"));
return;
}

Local<Value> data = info[0];
if (!data->IsString()) {
isolate->ThrowException(String::NewFromUtf8(isolate, "md5() requires a string argument"));
return;
}

size_t cnt = 0;

char *value = sMd5(*String::Utf8Value(data->ToString()), &cnt);
if (value == NULL) {
info.GetReturnValue().SetNull();
} else {
info.GetReturnValue().Set(String::NewFromUtf8(isolate, value));
free(value);
}

// record storage usage.
IncrCounter(isolate, isolate->GetCurrentContext(), cnt);
}

// Base64Callback
void Base64Callback(const FunctionCallbackInfo<Value> &info) {
Isolate *isolate = info.GetIsolate();

if (info.Length() != 1) {
isolate->ThrowException(String::NewFromUtf8(
isolate, "base64() requires only 1 argument"));
return;
}

Local<Value> data = info[0];
if (!data->IsString()) {
isolate->ThrowException(String::NewFromUtf8(isolate, "base64() requires a string argument"));
return;
}

size_t cnt = 0;

char *value = sBase64(*String::Utf8Value(data->ToString()), &cnt);
if (value == NULL) {
info.GetReturnValue().SetNull();
} else {
info.GetReturnValue().Set(String::NewFromUtf8(isolate, value));
free(value);
}

// record storage usage.
IncrCounter(isolate, isolate->GetCurrentContext(), cnt);
}
2 changes: 2 additions & 0 deletions nf/nvm/v8/lib/crypto.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,7 @@ void Sha256Callback(const FunctionCallbackInfo<Value> &info);
void Sha3256Callback(const FunctionCallbackInfo<Value> &info);
void Ripemd160Callback(const FunctionCallbackInfo<Value> &info);
void RecoverAddressCallback(const FunctionCallbackInfo<Value> &info);
void Md5Callback(const FunctionCallbackInfo<Value> &info);
void Base64Callback(const FunctionCallbackInfo<Value> &info);

#endif //_NEBULAS_NF_NVM_V8_LIB_CRYPTO_H_
18 changes: 18 additions & 0 deletions nf/nvm/v8/libjs/1.0.5/crypto.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,24 @@ Crypto.prototype = {
// sign: cipher hex string by private key, 130 chars
return this.nativeCrypto.recoverAddress(alg, hash, sign);
},

// case sensitive
md5: function(data) {
if (typeof data !== "string") {
throw new Error("input must be string");
}
// any string
return this.nativeCrypto.md5(data);
},

// case sensitive
base64: function(data) {
if (typeof data !== "string") {
throw new Error("input must be string");
}
// any string
return this.nativeCrypto.base64(data);
}
};

module.exports = new Crypto();

0 comments on commit f85a91f

Please sign in to comment.