func Test_Secp256_06b(t *testing.T) { pubkey1, seckey := GenerateKeyPair() msg := randentropy.GetEntropyCSPRNG(32) sig, _ := Sign(msg, seckey) fail_count := 0 for i := 0; i < TESTS; i++ { msg = randentropy.GetEntropyCSPRNG(32) pubkey2, _ := RecoverPubkey(msg, sig) if bytes.Equal(pubkey1, pubkey2) == true { t.Fail() } if pubkey2 != nil && VerifySignature(msg, sig, pubkey2) != nil { t.Fail() } if VerifySignature(msg, sig, pubkey1) == nil { t.Fail() } } if fail_count != 0 { fmt.Printf("ERROR: Accepted signature for %v of %v random messages\n", fail_count, TESTS) } }
func (ks keyStorePassphrase) StoreKey(key *Key, auth string) (err error) { authArray := []byte(auth) salt := randentropy.GetEntropyCSPRNG(32) derivedKey, err := scrypt.Key(authArray, salt, scryptN, scryptr, scryptp, scryptdkLen) if err != nil { return err } encryptKey := Sha3(derivedKey[:16])[:16] keyBytes := FromECDSA(key.PrivateKey) toEncrypt := PKCS7Pad(keyBytes) AES128Block, err := aes.NewCipher(encryptKey) if err != nil { return err } iv := randentropy.GetEntropyCSPRNG(aes.BlockSize) // 16 AES128CBCEncrypter := cipher.NewCBCEncrypter(AES128Block, iv) cipherText := make([]byte, len(toEncrypt)) AES128CBCEncrypter.CryptBlocks(cipherText, toEncrypt) mac := Sha3(derivedKey[16:32], cipherText) scryptParamsJSON := scryptParamsJSON{ N: scryptN, R: scryptr, P: scryptp, DkLen: scryptdkLen, Salt: hex.EncodeToString(salt), } cipherParamsJSON := cipherparamsJSON{ IV: hex.EncodeToString(iv), } cryptoStruct := cryptoJSON{ Cipher: "aes-128-cbc", CipherText: hex.EncodeToString(cipherText), CipherParams: cipherParamsJSON, KDF: "scrypt", KDFParams: scryptParamsJSON, MAC: hex.EncodeToString(mac), Version: "1", } encryptedKeyJSON := encryptedKeyJSON{ hex.EncodeToString(key.Address[:]), cryptoStruct, key.Id.String(), version, } keyJSON, err := json.Marshal(encryptedKeyJSON) if err != nil { return err } return WriteKeyFile(key.Address, ks.keysDirPath, keyJSON) }
func (ks keyStorePassphrase) StoreKey(key *Key, auth string) (err error) { authArray := []byte(auth) salt := randentropy.GetEntropyCSPRNG(32) derivedKey, err := scrypt.Key(authArray, salt, scryptN, scryptr, scryptp, scryptdkLen) if err != nil { return err } encryptKey := derivedKey[:16] keyBytes := FromECDSA(key.PrivateKey) iv := randentropy.GetEntropyCSPRNG(aes.BlockSize) // 16 cipherText, err := aesCTRXOR(encryptKey, keyBytes, iv) if err != nil { return err } mac := Sha3(derivedKey[16:32], cipherText) scryptParamsJSON := make(map[string]interface{}, 5) scryptParamsJSON["n"] = scryptN scryptParamsJSON["r"] = scryptr scryptParamsJSON["p"] = scryptp scryptParamsJSON["dklen"] = scryptdkLen scryptParamsJSON["salt"] = hex.EncodeToString(salt) cipherParamsJSON := cipherparamsJSON{ IV: hex.EncodeToString(iv), } cryptoStruct := cryptoJSON{ Cipher: "aes-128-ctr", CipherText: hex.EncodeToString(cipherText), CipherParams: cipherParamsJSON, KDF: "scrypt", KDFParams: scryptParamsJSON, MAC: hex.EncodeToString(mac), } encryptedKeyJSONV3 := encryptedKeyJSONV3{ hex.EncodeToString(key.Address[:]), cryptoStruct, key.Id.String(), version, } keyJSON, err := json.Marshal(encryptedKeyJSONV3) if err != nil { return err } return writeKeyFile(key.Address, ks.keysDirPath, keyJSON) }
func TestRandomMessagesAgainstValidSig(t *testing.T) { pubkey1, seckey := GenerateKeyPair() msg := randentropy.GetEntropyCSPRNG(32) sig, _ := Sign(msg, seckey) for i := 0; i < TestCount; i++ { msg = randentropy.GetEntropyCSPRNG(32) pubkey2, _ := RecoverPubkey(msg, sig) // recovery can sometimes work, but if so should always give wrong pubkey if bytes.Equal(pubkey1, pubkey2) { t.Fatalf("iteration: %d: pubkey mismatch: do NOT want %x: ", i, pubkey2) } } }
func Sign(msg []byte, seckey []byte) ([]byte, error) { nonce := randentropy.GetEntropyCSPRNG(32) var sig []byte = make([]byte, 65) var recid C.int var msg_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&msg[0])) var sig_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&sig[0])) var seckey_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&seckey[0])) var noncefp_ptr = &(*C.secp256k1_nonce_function_default) var ndata_ptr = unsafe.Pointer(&nonce[0]) if C.secp256k1_ec_seckey_verify(seckey_ptr) != C.int(1) { return nil, errors.New("Invalid secret key") } ret := C.secp256k1_ecdsa_sign_compact( msg_ptr, sig_ptr, seckey_ptr, noncefp_ptr, ndata_ptr, &recid) sig[64] = byte(int(recid)) if ret != C.int(1) { // nonce invalid, retry return Sign(msg, seckey) } return sig, nil }
func TestTimedUnlock(t *testing.T) { dir, ks := tmpKeyStore(t, crypto.NewKeyStorePassphrase) defer os.RemoveAll(dir) am := NewManager(ks) pass := "******" a1, err := am.NewAccount(pass) toSign := randentropy.GetEntropyCSPRNG(32) // Signing without passphrase fails because account is locked _, err = am.Sign(a1, toSign) if err != ErrLocked { t.Fatal("Signing should've failed with ErrLocked before unlocking, got ", err) } // Signing with passphrase works if err = am.TimedUnlock(a1.Address, pass, 100*time.Millisecond); err != nil { t.Fatal(err) } // Signing without passphrase works because account is temp unlocked _, err = am.Sign(a1, toSign) if err != nil { t.Fatal("Signing shouldn't return an error after unlocking, got ", err) } // Signing fails again after automatic locking time.Sleep(150 * time.Millisecond) _, err = am.Sign(a1, toSign) if err != ErrLocked { t.Fatal("Signing should've failed with ErrLocked timeout expired, got ", err) } }
func GenerateKeyPair() ([]byte, []byte) { var seckey []byte = randentropy.GetEntropyCSPRNG(32) var seckey_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&seckey[0])) var pubkey64 []byte = make([]byte, 64) // secp256k1_pubkey var pubkey65 []byte = make([]byte, 65) // 65 byte uncompressed pubkey pubkey64_ptr := (*C.secp256k1_pubkey)(unsafe.Pointer(&pubkey64[0])) pubkey65_ptr := (*C.uchar)(unsafe.Pointer(&pubkey65[0])) ret := C.secp256k1_ec_pubkey_create( context, pubkey64_ptr, seckey_ptr, ) if ret != C.int(1) { return GenerateKeyPair() // invalid secret, try again } var output_len C.size_t C.secp256k1_ec_pubkey_serialize( // always returns 1 context, pubkey65_ptr, &output_len, pubkey64_ptr, 0, // SECP256K1_EC_COMPRESSED ) return pubkey65, seckey }
//test pubkey recovery func Test_Secp256_02a(t *testing.T) { pubkey1, seckey1 := GenerateKeyPair() msg := randentropy.GetEntropyCSPRNG(32) sig, _ := Sign(msg, seckey1) if sig == nil { t.Fatal("Signature nil") } err := VerifySignature(msg, sig, pubkey1) if err != nil { t.Fatal("Signature invalid") } pubkey2, _ := RecoverPubkey(msg, sig) if len(pubkey1) != len(pubkey2) { t.Fatal() } for i, _ := range pubkey1 { if pubkey1[i] != pubkey2[i] { t.Fatal() } } if bytes.Equal(pubkey1, pubkey2) == false { t.Fatal() } }
func Test_Secp256_06a_alt0(t *testing.T) { pubkey1, seckey := GenerateKeyPair() msg := randentropy.GetEntropyCSPRNG(32) sig, _ := Sign(msg, seckey) if sig == nil { t.Fail() } if len(sig) != 65 { t.Fail() } for i := 0; i < TESTS; i++ { sig = randSig() pubkey2, _ := RecoverPubkey(msg, sig) if bytes.Equal(pubkey1, pubkey2) == true { t.Fail() } if pubkey2 != nil && VerifySignature(msg, sig, pubkey2) != nil { t.Fail() } if VerifySignature(msg, sig, pubkey1) == nil { t.Fail() } } }
func signAndRecoverWithRandomMessages(t *testing.T, keys func() ([]byte, []byte)) { for i := 0; i < TestCount; i++ { pubkey1, seckey := keys() msg := randentropy.GetEntropyCSPRNG(32) sig, err := Sign(msg, seckey) if err != nil { t.Fatalf("signature error: %s", err) } if sig == nil { t.Fatal("signature is nil") } compactSigCheck(t, sig) // TODO: why do we flip around the recovery id? sig[len(sig)-1] %= 4 pubkey2, err := RecoverPubkey(msg, sig) if err != nil { t.Fatalf("recover error: %s", err) } if pubkey2 == nil { t.Error("pubkey is nil") } if !bytes.Equal(pubkey1, pubkey2) { t.Fatalf("pubkey mismatch: want: %x have: %x", pubkey1, pubkey2) } } }
func Test_Secp256_00(t *testing.T) { var nonce []byte = randentropy.GetEntropyCSPRNG(32) //going to get bitcoins stolen! if len(nonce) != 32 { t.Fatal() } }
// EncryptKey encrypts a key using the specified scrypt parameters into a json // blob that can be decrypted later on. func EncryptKey(key *Key, auth string, scryptN, scryptP int) ([]byte, error) { authArray := []byte(auth) salt := randentropy.GetEntropyCSPRNG(32) derivedKey, err := scrypt.Key(authArray, salt, scryptN, scryptR, scryptP, scryptDKLen) if err != nil { return nil, err } encryptKey := derivedKey[:16] keyBytes := crypto.FromECDSA(key.PrivateKey) iv := randentropy.GetEntropyCSPRNG(aes.BlockSize) // 16 cipherText, err := aesCTRXOR(encryptKey, keyBytes, iv) if err != nil { return nil, err } mac := crypto.Keccak256(derivedKey[16:32], cipherText) scryptParamsJSON := make(map[string]interface{}, 5) scryptParamsJSON["n"] = scryptN scryptParamsJSON["r"] = scryptR scryptParamsJSON["p"] = scryptP scryptParamsJSON["dklen"] = scryptDKLen scryptParamsJSON["salt"] = hex.EncodeToString(salt) cipherParamsJSON := cipherparamsJSON{ IV: hex.EncodeToString(iv), } cryptoStruct := cryptoJSON{ Cipher: "aes-128-ctr", CipherText: hex.EncodeToString(cipherText), CipherParams: cipherParamsJSON, KDF: "scrypt", KDFParams: scryptParamsJSON, MAC: hex.EncodeToString(mac), } encryptedKeyJSONV3 := encryptedKeyJSONV3{ hex.EncodeToString(key.Address[:]), cryptoStruct, key.Id.String(), version, } return json.Marshal(encryptedKeyJSONV3) }
func BenchmarkSign(b *testing.B) { for i := 0; i < b.N; i++ { _, seckey := GenerateKeyPair() msg := randentropy.GetEntropyCSPRNG(32) b.StartTimer() _, e := Sign(msg, seckey) err = e b.StopTimer() } }
func TestInvalidRecoveryID(t *testing.T) { _, seckey := GenerateKeyPair() msg := randentropy.GetEntropyCSPRNG(32) sig, _ := Sign(msg, seckey) sig[64] = 99 _, err := RecoverPubkey(msg, sig) if err != ErrInvalidRecoveryID { t.Fatalf("got %q, want %q", err, ErrInvalidRecoveryID) } }
// godep go test -v -run=XXX -bench=BenchmarkSignRandomInputEachRound // add -benchtime=10s to benchmark longer for more accurate average func BenchmarkSignRandomInputEachRound(b *testing.B) { for i := 0; i < b.N; i++ { b.StopTimer() _, seckey := GenerateKeyPair() msg := randentropy.GetEntropyCSPRNG(32) b.StartTimer() if _, err := Sign(msg, seckey); err != nil { b.Fatal(err) } } }
//test random messages for the same pub/private key func Test_Secp256_03(t *testing.T) { _, seckey := GenerateKeyPair() for i := 0; i < TESTS; i++ { msg := randentropy.GetEntropyCSPRNG(32) sig, _ := Sign(msg, seckey) CompactSigTest(sig) sig[len(sig)-1] %= 4 pubkey2, _ := RecoverPubkey(msg, sig) if pubkey2 == nil { t.Fail() } } }
func TestSign(t *testing.T) { dir, ks := tmpKeyStore(t, crypto.NewKeyStorePlain) defer os.RemoveAll(dir) am := NewManager(ks) pass := "" // not used but required by API a1, err := am.NewAccount(pass) toSign := randentropy.GetEntropyCSPRNG(32) am.Unlock(a1.Address, "") _, err = am.Sign(a1, toSign) if err != nil { t.Fatal(err) } }
func TestSignAndRecover(t *testing.T) { pubkey1, seckey := GenerateKeyPair() msg := randentropy.GetEntropyCSPRNG(32) sig, err := Sign(msg, seckey) if err != nil { t.Errorf("signature error: %s", err) } pubkey2, err := RecoverPubkey(msg, sig) if err != nil { t.Errorf("recover error: %s", err) } if !bytes.Equal(pubkey1, pubkey2) { t.Errorf("pubkey mismatch: want: %x have: %x", pubkey1, pubkey2) } }
func TestRecoveryOfRandomSignature(t *testing.T) { pubkey1, seckey := GenerateKeyPair() msg := randentropy.GetEntropyCSPRNG(32) sig, err := Sign(msg, seckey) if err != nil { t.Errorf("signature error: %s", err) } for i := 0; i < TestCount; i++ { sig = randSig() pubkey2, _ := RecoverPubkey(msg, sig) // recovery can sometimes work, but if so should always give wrong pubkey if bytes.Equal(pubkey1, pubkey2) { t.Fatalf("iteration: %d: pubkey mismatch: do NOT want %x: ", i, pubkey2) } } }
func Sign(msg []byte, seckey []byte) ([]byte, error) { msg_ptr := (*C.uchar)(unsafe.Pointer(&msg[0])) seckey_ptr := (*C.uchar)(unsafe.Pointer(&seckey[0])) sig := make([]byte, 65) sig_ptr := (*C.secp256k1_ecdsa_recoverable_signature)(unsafe.Pointer(&sig[0])) nonce := randentropy.GetEntropyCSPRNG(32) ndata_ptr := unsafe.Pointer(&nonce[0]) noncefp_ptr := &(*C.secp256k1_nonce_function_default) if C.secp256k1_ec_seckey_verify(context, seckey_ptr) != C.int(1) { return nil, errors.New("Invalid secret key") } ret := C.secp256k1_ecdsa_sign_recoverable( context, sig_ptr, msg_ptr, seckey_ptr, noncefp_ptr, ndata_ptr, ) if ret == C.int(0) { return Sign(msg, seckey) //invalid secret, try again } sig_serialized := make([]byte, 65) sig_serialized_ptr := (*C.uchar)(unsafe.Pointer(&sig_serialized[0])) var recid C.int C.secp256k1_ecdsa_recoverable_signature_serialize_compact( context, sig_serialized_ptr, // 64 byte compact signature &recid, sig_ptr, // 65 byte "recoverable" signature ) sig_serialized[64] = byte(int(recid)) // add back recid to get 65 bytes sig return sig_serialized, nil }
//test random messages for different pub/private keys func Test_Secp256_04(t *testing.T) { for i := 0; i < TESTS; i++ { pubkey1, seckey := GenerateKeyPair() msg := randentropy.GetEntropyCSPRNG(32) sig, _ := Sign(msg, seckey) CompactSigTest(sig) if sig[len(sig)-1] >= 4 { t.Fail() } pubkey2, _ := RecoverPubkey(msg, sig) if pubkey2 == nil { t.Fail() } if bytes.Equal(pubkey1, pubkey2) == false { t.Fail() } } }
func GenerateKeyPair() ([]byte, []byte) { pubkey_len := C.int(65) const seckey_len = 32 var pubkey []byte = make([]byte, pubkey_len) var seckey []byte = randentropy.GetEntropyCSPRNG(seckey_len) var pubkey_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&pubkey[0])) var seckey_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&seckey[0])) ret := C.secp256k1_ec_pubkey_create( pubkey_ptr, &pubkey_len, seckey_ptr, 0) if ret != C.int(1) { return GenerateKeyPair() //invalid secret, try again } return pubkey, seckey }
//test size of messages func Test_Secp256_02s(t *testing.T) { pubkey, seckey := GenerateKeyPair() msg := randentropy.GetEntropyCSPRNG(32) sig, _ := Sign(msg, seckey) CompactSigTest(sig) if sig == nil { t.Fatal("Signature nil") } if len(pubkey) != 65 { t.Fail() } if len(seckey) != 32 { t.Fail() } if len(sig) != 64+1 { t.Fail() } if int(sig[64]) > 4 { t.Fail() } //should be 0 to 4 }
//test signing message func Test_Secp256_02(t *testing.T) { pubkey1, seckey := GenerateKeyPair() msg := randentropy.GetEntropyCSPRNG(32) sig, _ := Sign(msg, seckey) if sig == nil { t.Fatal("Signature nil") } pubkey2, _ := RecoverPubkey(msg, sig) if pubkey2 == nil { t.Fatal("Recovered pubkey invalid") } if bytes.Equal(pubkey1, pubkey2) == false { t.Fatal("Recovered pubkey does not match") } err := VerifySignature(msg, sig, pubkey1) if err != nil { t.Fatal("Signature invalid") } }
func TestSignatureValidity(t *testing.T) { pubkey, seckey := GenerateKeyPair() msg := randentropy.GetEntropyCSPRNG(32) sig, err := Sign(msg, seckey) if err != nil { t.Errorf("signature error: %s", err) } compactSigCheck(t, sig) if len(pubkey) != 65 { t.Errorf("pubkey length mismatch: want: 65 have: %d", len(pubkey)) } if len(seckey) != 32 { t.Errorf("seckey length mismatch: want: 32 have: %d", len(seckey)) } if len(sig) != 65 { t.Errorf("sig length mismatch: want: 65 have: %d", len(sig)) } recid := int(sig[64]) if recid > 4 || recid < 0 { t.Errorf("sig recid mismatch: want: within 0 to 4 have: %d", int(sig[64])) } }
func randSig() []byte { sig := randentropy.GetEntropyCSPRNG(65) sig[32] &= 0x70 sig[64] %= 4 return sig }