-
Notifications
You must be signed in to change notification settings - Fork 32
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
9 changed files
with
325 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
This repo requires the installation of the Golang compiler on the system in order to run the | ||
presubmit script and the provided Go FFI and test. To install Go under Ubuntu, run the following: | ||
|
||
``sudo apt install golang-go`` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,195 @@ | ||
package crypto_lib | ||
|
||
import "encoding/hex" | ||
import ( | ||
"fmt" | ||
"math/big" | ||
) | ||
/* | ||
#cgo CFLAGS: -I. | ||
#cgo LDFLAGS: -L./.. -lcrypto_c_exports -Wl,-rpath=./. | ||
#include <stdlib.h> | ||
#include "../ecdsa.h" | ||
#include "../pedersen_hash.h" | ||
*/ | ||
import "C" | ||
import "unsafe" | ||
|
||
|
||
const curveOrder = "800000000000010ffffffffffffffffb781126dcae7b2321e66a241adc64d2f" | ||
|
||
/* | ||
Computes the component s of a signature given the component w. | ||
*/ | ||
func invertOnCurve(w string) string { | ||
w_big_int := new(big.Int) | ||
w_big_int.SetString(w[2:], 16) | ||
order := new(big.Int) | ||
order.SetString(curveOrder, 16) | ||
w_big_int.ModInverse(w_big_int, order) | ||
s := fmt.Sprintf("0x0%x", w_big_int) | ||
return s | ||
} | ||
|
||
/* | ||
Given a hex string reverses its endian represenation. | ||
*/ | ||
func reverseHexEndianRepresentation(s string) string { | ||
rns := []rune(s) | ||
for i, j := 0, len(rns)-2; i < j; i, j = i+2, j-2 { | ||
rns[i], rns[j] = rns[j], rns[i] | ||
rns[i+1], rns[j+1] = rns[j+1], rns[i+1] | ||
} | ||
return string(rns) | ||
} | ||
|
||
/* | ||
Pads the given hex string with leading zeroes so that its length is 64 characters (32 bytes). | ||
*/ | ||
func padHexString(s string) string { | ||
padded := fmt.Sprintf("0x%064s", s[2:]) | ||
return padded | ||
} | ||
|
||
/* | ||
Computes the StarkWare version of the Pedersen hash of x and y. | ||
Full specification of the hash function can be found here: | ||
https://docs.starkware.co/starkex-docs/crypto/pedersen-hash-function | ||
*/ | ||
func Hash(input1, input2 string) string { | ||
input1_dec, _ := hex.DecodeString(reverseHexEndianRepresentation(input1)) | ||
input2_dec, _ := hex.DecodeString(reverseHexEndianRepresentation(input2)) | ||
in1 := C.CBytes(input1_dec) | ||
in2 := C.CBytes(input2_dec) | ||
var o [1024]byte | ||
out := C.CBytes(o[:]) | ||
|
||
res := C.Hash( | ||
(*C.char)(unsafe.Pointer(in1)), | ||
(*C.char)(unsafe.Pointer(in2)), | ||
(*C.char)(unsafe.Pointer(out))) | ||
|
||
if res != 0 { | ||
fmt.Printf("Pedersen hash encountered an error: %s\n", C.GoBytes(unsafe.Pointer(out), 1024)) | ||
C.free(unsafe.Pointer(in1)) | ||
C.free(unsafe.Pointer(in2)) | ||
C.free(unsafe.Pointer(out)) | ||
return "" | ||
} | ||
|
||
hash_result := "0x" + reverseHexEndianRepresentation( | ||
hex.EncodeToString(C.GoBytes(unsafe.Pointer(out), 32))) | ||
|
||
C.free(unsafe.Pointer(in1)) | ||
C.free(unsafe.Pointer(in2)) | ||
C.free(unsafe.Pointer(out)) | ||
|
||
return hash_result | ||
} | ||
|
||
/* | ||
Deduces the public key given a private key. | ||
*/ | ||
func GetPublicKey(private_key string) string { | ||
private_key_dec, _ := hex.DecodeString( | ||
reverseHexEndianRepresentation(padHexString(private_key))) | ||
private_key_bytes := C.CBytes(private_key_dec) | ||
var o [1024]byte | ||
out := C.CBytes(o[:]) | ||
|
||
res := C.GetPublicKey( | ||
(*C.char)(unsafe.Pointer(private_key_bytes)), (*C.char)(unsafe.Pointer(out))) | ||
|
||
if res != 0 { | ||
fmt.Printf("GetPublicKey encountered an error: %s\n", C.GoBytes(unsafe.Pointer(out), 1024)) | ||
C.free(unsafe.Pointer(private_key_bytes)) | ||
C.free(unsafe.Pointer(out)) | ||
return "" | ||
} | ||
|
||
public_key_result := "0x" + reverseHexEndianRepresentation( | ||
hex.EncodeToString(C.GoBytes(unsafe.Pointer(out), 32))) | ||
|
||
C.free(unsafe.Pointer(private_key_bytes)) | ||
C.free(unsafe.Pointer(out)) | ||
|
||
return public_key_result | ||
} | ||
|
||
/* | ||
Verifies ECDSA signature of a given message hash z with a given public key. | ||
Returns true if public_key signs the message. | ||
NOTE: This function assumes that the public_key is on the curve. | ||
*/ | ||
func Verify(stark_key, msg_hash, r, s string) bool { | ||
stark_key_dec, _ := hex.DecodeString(reverseHexEndianRepresentation(padHexString(stark_key))) | ||
stark_key_bytes := C.CBytes(stark_key_dec) | ||
|
||
message_dec, _ := hex.DecodeString(reverseHexEndianRepresentation(padHexString(msg_hash))) | ||
message_bytes := C.CBytes(message_dec) | ||
|
||
r_dec, _ := hex.DecodeString(reverseHexEndianRepresentation(padHexString(r))) | ||
r_bytes := C.CBytes(r_dec) | ||
|
||
w := invertOnCurve(s) | ||
w_dec, _ := hex.DecodeString(reverseHexEndianRepresentation(padHexString(w))) | ||
w_bytes := C.CBytes(w_dec) | ||
|
||
res := C.Verify( | ||
(*C.char)(unsafe.Pointer(stark_key_bytes)), | ||
(*C.char)(unsafe.Pointer(message_bytes)), | ||
(*C.char)(unsafe.Pointer(r_bytes)), | ||
(*C.char)(unsafe.Pointer(w_bytes))) | ||
|
||
C.free(unsafe.Pointer(stark_key_bytes)) | ||
C.free(unsafe.Pointer(message_bytes)) | ||
C.free(unsafe.Pointer(r_bytes)) | ||
C.free(unsafe.Pointer(w_bytes)) | ||
|
||
if res == 0 { | ||
return false | ||
} | ||
return true | ||
} | ||
|
||
/* | ||
Signs the given message hash with the provided private_key, with randomness k. | ||
NOTE: k should be a strong cryptographical random, and not repeat. | ||
See: https://tools.ietf.org/html/rfc6979. | ||
*/ | ||
func Sign(private_key, message, k string) (string, string) { | ||
private_key_dec, _ := hex.DecodeString( | ||
reverseHexEndianRepresentation(padHexString(private_key))) | ||
private_key_bytes := C.CBytes(private_key_dec) | ||
|
||
message_dec, _ := hex.DecodeString(reverseHexEndianRepresentation(padHexString(message))) | ||
message_bytes := C.CBytes(message_dec) | ||
|
||
k_dec, _ := hex.DecodeString(reverseHexEndianRepresentation(padHexString(k))) | ||
k_bytes := C.CBytes(k_dec) | ||
|
||
var o [1024]byte | ||
out := C.CBytes(o[:]) | ||
|
||
C.Sign( | ||
(*C.char)(unsafe.Pointer(private_key_bytes)), | ||
(*C.char)(unsafe.Pointer(message_bytes)), | ||
(*C.char)(unsafe.Pointer(k_bytes)), | ||
(*C.char)(unsafe.Pointer(out))) | ||
|
||
res := reverseHexEndianRepresentation(hex.EncodeToString(C.GoBytes(unsafe.Pointer(out), 64))) | ||
signature_w := "0x" + res[0:64] | ||
signature_r := "0x" + res[64:] | ||
|
||
signature_s := invertOnCurve(signature_w) | ||
|
||
C.free(unsafe.Pointer(private_key_bytes)) | ||
C.free(unsafe.Pointer(message_bytes)) | ||
C.free(unsafe.Pointer(k_bytes)) | ||
C.free(unsafe.Pointer(out)) | ||
|
||
return signature_r, signature_s | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
package main | ||
|
||
import "./crypto_lib" | ||
import "testing" | ||
|
||
func TestHash(t *testing.T) { | ||
res := crypto_lib.Hash( | ||
"0x03d937c035c878245caf64531a5756109c53068da139362728feb561405371cb", | ||
"0x0208a0a10250e382e1e4bbe2880906c2791bf6275695e02fbbc6aeff9cd8b31a") | ||
|
||
expected_hash := "0x030e480bed5fe53fa909cc0f8c4d99b8f9f2c016be4c41e13a4848797979c662" | ||
if res != expected_hash { | ||
t.Errorf("Hash error: expected %s but got %s.", expected_hash, res) | ||
} | ||
} | ||
|
||
func TestGetPublicKey(t *testing.T) { | ||
res := crypto_lib.GetPublicKey( | ||
"0x03c1e9550e66958296d11b60f8e8e7a7ad990d07fa65d5f7652c4a6c87d4e3cc") | ||
|
||
expected_key := "0x077a3b314db07c45076d11f62b6f9e748a39790441823307743cf00d6597ea43" | ||
if res != expected_key { | ||
t.Errorf("GetPublicKey error: expected %s but got %s.", expected_key, res) | ||
} | ||
|
||
res = crypto_lib.GetPublicKey("0x12") | ||
|
||
expected_key = "0x019661066e96a8b9f06a1d136881ee924dfb6a885239caa5fd3f87a54c6b25c4" | ||
if res != expected_key { | ||
t.Errorf("GetPublicKey error: expected %s but got %s.", expected_key, res) | ||
} | ||
} | ||
|
||
func TestVerify(t *testing.T) { | ||
res := crypto_lib.Verify( | ||
"0x1ef15c18599971b7beced415a40f0c7deacfd9b0d1819e03d723d8bc943cfca", | ||
"0x2", | ||
"0x411494b501a98abd8262b0da1351e17899a0c4ef23dd2f96fec5ba847310b20", | ||
"0x405c3191ab3883ef2b763af35bc5f5d15b3b4e99461d70e84c654a351a7c81b") | ||
if !(res) { | ||
t.Errorf("Verify error: valid message was not verified correctly.") | ||
} | ||
|
||
res = crypto_lib.Verify( | ||
"0x077a4b314db07c45076d11f62b6f9e748a39790441823307743cf00d6597ea43", | ||
"0x0397e76d1667c4454bfb83514e120583af836f8e32a516765497823eabe16a3f", | ||
"0x0173fd03d8b008ee7432977ac27d1e9d1a1f6c98b1a2f05fa84a21c84c44e882", | ||
"0x01f2c44a7798f55192f153b4c48ea5c1241fbb69e6132cc8a0da9c5b62a4286e") | ||
if (res) { | ||
t.Errorf("Verify error: invalid message was not rejected.") | ||
} | ||
} | ||
|
||
func TestSign(t *testing.T) { | ||
r, s := crypto_lib.Sign("0x1", "0x2", "0x3") | ||
public_key := crypto_lib.GetPublicKey("0x1") | ||
res := crypto_lib.Verify(public_key, "0x2", r, s) | ||
if !(res) { | ||
t.Errorf("Sign error: signature rejected by verification.") | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
#ifndef STARKWARE_CRYPTO_FFI_ECDSA_H_ | ||
#define STARKWARE_CRYPTO_FFI_ECDSA_H_ | ||
|
||
int GetPublicKey(const char* private_key, char* out); | ||
|
||
int Verify(const char* stark_key, const char* msg_hash, const char* r_bytes, const char* w_bytes); | ||
|
||
int Sign(const char* private_key, const char* message, const char* k, char* out); | ||
|
||
#endif // STARKWARE_CRYPTO_FFI_ECDSA_H_ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
#ifndef STARKWARE_CRYPTO_FFI_PEDERSEN_HASH_H_ | ||
#define STARKWARE_CRYPTO_FFI_PEDERSEN_HASH_H_ | ||
|
||
int Hash(const char* in1, const char* in2, char* out); | ||
|
||
#endif // STARKWARE_CRYPTO_FFI_PEDERSEN_HASH_H_ |