Revert "delete everything"
This reverts commit 96a3502126
.
# Conflicts:
# CHANGELOG.md
# Gopkg.lock
# Gopkg.toml
# LICENSE
# Makefile
# README.md
This commit is contained in:
parent
368c236c75
commit
eedd20f4d5
37
amino.go
37
amino.go
|
@ -1,37 +0,0 @@
|
||||||
package crypto
|
|
||||||
|
|
||||||
import (
|
|
||||||
amino "github.com/tendermint/go-amino"
|
|
||||||
)
|
|
||||||
|
|
||||||
var cdc = amino.NewCodec()
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
// NOTE: It's important that there be no conflicts here,
|
|
||||||
// as that would change the canonical representations,
|
|
||||||
// and therefore change the address.
|
|
||||||
// TODO: Add feature to go-amino to ensure that there
|
|
||||||
// are no conflicts.
|
|
||||||
RegisterAmino(cdc)
|
|
||||||
}
|
|
||||||
|
|
||||||
// RegisterAmino registers all go-crypto related types in the given (amino) codec.
|
|
||||||
func RegisterAmino(cdc *amino.Codec) {
|
|
||||||
cdc.RegisterInterface((*PubKey)(nil), nil)
|
|
||||||
cdc.RegisterConcrete(PubKeyEd25519{},
|
|
||||||
"tendermint/PubKeyEd25519", nil)
|
|
||||||
cdc.RegisterConcrete(PubKeySecp256k1{},
|
|
||||||
"tendermint/PubKeySecp256k1", nil)
|
|
||||||
|
|
||||||
cdc.RegisterInterface((*PrivKey)(nil), nil)
|
|
||||||
cdc.RegisterConcrete(PrivKeyEd25519{},
|
|
||||||
"tendermint/PrivKeyEd25519", nil)
|
|
||||||
cdc.RegisterConcrete(PrivKeySecp256k1{},
|
|
||||||
"tendermint/PrivKeySecp256k1", nil)
|
|
||||||
|
|
||||||
cdc.RegisterInterface((*Signature)(nil), nil)
|
|
||||||
cdc.RegisterConcrete(SignatureEd25519{},
|
|
||||||
"tendermint/SignatureEd25519", nil)
|
|
||||||
cdc.RegisterConcrete(SignatureSecp256k1{},
|
|
||||||
"tendermint/SignatureSecp256k1", nil)
|
|
||||||
}
|
|
39
armor.go
39
armor.go
|
@ -1,39 +0,0 @@
|
||||||
package crypto
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"fmt"
|
|
||||||
"io/ioutil"
|
|
||||||
|
|
||||||
"golang.org/x/crypto/openpgp/armor"
|
|
||||||
)
|
|
||||||
|
|
||||||
func EncodeArmor(blockType string, headers map[string]string, data []byte) string {
|
|
||||||
buf := new(bytes.Buffer)
|
|
||||||
w, err := armor.Encode(buf, blockType, headers)
|
|
||||||
if err != nil {
|
|
||||||
panic(fmt.Errorf("could not encode ascii armor: %s", err))
|
|
||||||
}
|
|
||||||
_, err = w.Write(data)
|
|
||||||
if err != nil {
|
|
||||||
panic(fmt.Errorf("could not encode ascii armor: %s", err))
|
|
||||||
}
|
|
||||||
err = w.Close()
|
|
||||||
if err != nil {
|
|
||||||
panic(fmt.Errorf("could not encode ascii armor: %s", err))
|
|
||||||
}
|
|
||||||
return buf.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
func DecodeArmor(armorStr string) (blockType string, headers map[string]string, data []byte, err error) {
|
|
||||||
buf := bytes.NewBufferString(armorStr)
|
|
||||||
block, err := armor.Decode(buf)
|
|
||||||
if err != nil {
|
|
||||||
return "", nil, nil, err
|
|
||||||
}
|
|
||||||
data, err = ioutil.ReadAll(block.Body)
|
|
||||||
if err != nil {
|
|
||||||
return "", nil, nil, err
|
|
||||||
}
|
|
||||||
return block.Type, block.Header, data, nil
|
|
||||||
}
|
|
|
@ -1,20 +0,0 @@
|
||||||
package crypto
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestSimpleArmor(t *testing.T) {
|
|
||||||
blockType := "MINT TEST"
|
|
||||||
data := []byte("somedata")
|
|
||||||
armorStr := EncodeArmor(blockType, nil, data)
|
|
||||||
|
|
||||||
// Decode armorStr and test for equivalence.
|
|
||||||
blockType2, _, data2, err := DecodeArmor(armorStr)
|
|
||||||
require.Nil(t, err, "%+v", err)
|
|
||||||
assert.Equal(t, blockType, blockType2)
|
|
||||||
assert.Equal(t, data, data2)
|
|
||||||
}
|
|
48
doc.go
48
doc.go
|
@ -1,48 +0,0 @@
|
||||||
/*
|
|
||||||
go-crypto is a customized/convenience cryptography package
|
|
||||||
for supporting Tendermint.
|
|
||||||
|
|
||||||
It wraps select functionality of equivalent functions in the
|
|
||||||
Go standard library, for easy usage with our libraries.
|
|
||||||
|
|
||||||
Keys:
|
|
||||||
|
|
||||||
All key generation functions return an instance of the PrivKey interface
|
|
||||||
which implements methods
|
|
||||||
|
|
||||||
AssertIsPrivKeyInner()
|
|
||||||
Bytes() []byte
|
|
||||||
Sign(msg []byte) Signature
|
|
||||||
PubKey() PubKey
|
|
||||||
Equals(PrivKey) bool
|
|
||||||
Wrap() PrivKey
|
|
||||||
|
|
||||||
From the above method we can:
|
|
||||||
a) Retrieve the public key if needed
|
|
||||||
|
|
||||||
pubKey := key.PubKey()
|
|
||||||
|
|
||||||
For example:
|
|
||||||
privKey, err := crypto.GenPrivKeyEd25519()
|
|
||||||
if err != nil {
|
|
||||||
...
|
|
||||||
}
|
|
||||||
pubKey := privKey.PubKey()
|
|
||||||
...
|
|
||||||
// And then you can use the private and public key
|
|
||||||
doSomething(privKey, pubKey)
|
|
||||||
|
|
||||||
|
|
||||||
We also provide hashing wrappers around algorithms:
|
|
||||||
|
|
||||||
Sha256
|
|
||||||
sum := crypto.Sha256([]byte("This is Tendermint"))
|
|
||||||
fmt.Printf("%x\n", sum)
|
|
||||||
|
|
||||||
Ripemd160
|
|
||||||
sum := crypto.Ripemd160([]byte("This is consensus"))
|
|
||||||
fmt.Printf("%x\n", sum)
|
|
||||||
*/
|
|
||||||
package crypto
|
|
||||||
|
|
||||||
// TODO: Add more docs in here
|
|
119
encode_test.go
119
encode_test.go
|
@ -1,119 +0,0 @@
|
||||||
package crypto
|
|
||||||
|
|
||||||
import (
|
|
||||||
"os"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
)
|
|
||||||
|
|
||||||
type byter interface {
|
|
||||||
Bytes() []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
func checkAminoBinary(t *testing.T, src byter, dst interface{}, size int) {
|
|
||||||
// Marshal to binary bytes.
|
|
||||||
bz, err := cdc.MarshalBinaryBare(src)
|
|
||||||
require.Nil(t, err, "%+v", err)
|
|
||||||
// Make sure this is compatible with current (Bytes()) encoding.
|
|
||||||
assert.Equal(t, src.Bytes(), bz, "Amino binary vs Bytes() mismatch")
|
|
||||||
// Make sure we have the expected length.
|
|
||||||
if size != -1 {
|
|
||||||
assert.Equal(t, size, len(bz), "Amino binary size mismatch")
|
|
||||||
}
|
|
||||||
// Unmarshal.
|
|
||||||
err = cdc.UnmarshalBinaryBare(bz, dst)
|
|
||||||
require.Nil(t, err, "%+v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func checkAminoJSON(t *testing.T, src interface{}, dst interface{}, isNil bool) {
|
|
||||||
// Marshal to JSON bytes.
|
|
||||||
js, err := cdc.MarshalJSON(src)
|
|
||||||
require.Nil(t, err, "%+v", err)
|
|
||||||
if isNil {
|
|
||||||
assert.Equal(t, string(js), `null`)
|
|
||||||
} else {
|
|
||||||
assert.Contains(t, string(js), `"type":`)
|
|
||||||
assert.Contains(t, string(js), `"value":`)
|
|
||||||
}
|
|
||||||
// Unmarshal.
|
|
||||||
err = cdc.UnmarshalJSON(js, dst)
|
|
||||||
require.Nil(t, err, "%+v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func ExamplePrintRegisteredTypes() {
|
|
||||||
cdc.PrintTypes(os.Stdout)
|
|
||||||
// Output: | Type | Name | Prefix | Length | Notes |
|
|
||||||
//| ---- | ---- | ------ | ----- | ------ |
|
|
||||||
//| PubKeyEd25519 | tendermint/PubKeyEd25519 | 0x1624DE64 | 0x20 | |
|
|
||||||
//| PubKeySecp256k1 | tendermint/PubKeySecp256k1 | 0xEB5AE987 | 0x21 | |
|
|
||||||
//| PrivKeyEd25519 | tendermint/PrivKeyEd25519 | 0xA3288910 | 0x40 | |
|
|
||||||
//| PrivKeySecp256k1 | tendermint/PrivKeySecp256k1 | 0xE1B0F79B | 0x20 | |
|
|
||||||
//| SignatureEd25519 | tendermint/SignatureEd25519 | 0x2031EA53 | 0x40 | |
|
|
||||||
//| SignatureSecp256k1 | tendermint/SignatureSecp256k1 | 0x7FC4A495 | variable | |
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestKeyEncodings(t *testing.T) {
|
|
||||||
cases := []struct {
|
|
||||||
privKey PrivKey
|
|
||||||
privSize, pubSize int // binary sizes
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
privKey: GenPrivKeyEd25519(),
|
|
||||||
privSize: 69,
|
|
||||||
pubSize: 37,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
privKey: GenPrivKeySecp256k1(),
|
|
||||||
privSize: 37,
|
|
||||||
pubSize: 38,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tc := range cases {
|
|
||||||
|
|
||||||
// Check (de/en)codings of PrivKeys.
|
|
||||||
var priv2, priv3 PrivKey
|
|
||||||
checkAminoBinary(t, tc.privKey, &priv2, tc.privSize)
|
|
||||||
assert.EqualValues(t, tc.privKey, priv2)
|
|
||||||
checkAminoJSON(t, tc.privKey, &priv3, false) // TODO also check Prefix bytes.
|
|
||||||
assert.EqualValues(t, tc.privKey, priv3)
|
|
||||||
|
|
||||||
// Check (de/en)codings of Signatures.
|
|
||||||
var sig1, sig2, sig3 Signature
|
|
||||||
sig1, err := tc.privKey.Sign([]byte("something"))
|
|
||||||
assert.NoError(t, err)
|
|
||||||
checkAminoBinary(t, sig1, &sig2, -1) // Siganture size changes for Secp anyways.
|
|
||||||
assert.EqualValues(t, sig1, sig2)
|
|
||||||
checkAminoJSON(t, sig1, &sig3, false) // TODO also check Prefix bytes.
|
|
||||||
assert.EqualValues(t, sig1, sig3)
|
|
||||||
|
|
||||||
// Check (de/en)codings of PubKeys.
|
|
||||||
pubKey := tc.privKey.PubKey()
|
|
||||||
var pub2, pub3 PubKey
|
|
||||||
checkAminoBinary(t, pubKey, &pub2, tc.pubSize)
|
|
||||||
assert.EqualValues(t, pubKey, pub2)
|
|
||||||
checkAminoJSON(t, pubKey, &pub3, false) // TODO also check Prefix bytes.
|
|
||||||
assert.EqualValues(t, pubKey, pub3)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestNilEncodings(t *testing.T) {
|
|
||||||
|
|
||||||
// Check nil Signature.
|
|
||||||
var a, b Signature
|
|
||||||
checkAminoJSON(t, &a, &b, true)
|
|
||||||
assert.EqualValues(t, a, b)
|
|
||||||
|
|
||||||
// Check nil PubKey.
|
|
||||||
var c, d PubKey
|
|
||||||
checkAminoJSON(t, &c, &d, true)
|
|
||||||
assert.EqualValues(t, c, d)
|
|
||||||
|
|
||||||
// Check nil PrivKey.
|
|
||||||
var e, f PrivKey
|
|
||||||
checkAminoJSON(t, &e, &f, true)
|
|
||||||
assert.EqualValues(t, e, f)
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,35 +0,0 @@
|
||||||
// Copyright 2017 Tendermint. All Rights Reserved.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package crypto_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/tendermint/go-crypto"
|
|
||||||
)
|
|
||||||
|
|
||||||
func ExampleSha256() {
|
|
||||||
sum := crypto.Sha256([]byte("This is Tendermint"))
|
|
||||||
fmt.Printf("%x\n", sum)
|
|
||||||
// Output:
|
|
||||||
// f91afb642f3d1c87c17eb01aae5cb65c242dfdbe7cf1066cc260f4ce5d33b94e
|
|
||||||
}
|
|
||||||
|
|
||||||
func ExampleRipemd160() {
|
|
||||||
sum := crypto.Ripemd160([]byte("This is Tendermint"))
|
|
||||||
fmt.Printf("%x\n", sum)
|
|
||||||
// Output:
|
|
||||||
// 051e22663e8f0fd2f2302f1210f954adff009005
|
|
||||||
}
|
|
18
hash.go
18
hash.go
|
@ -1,18 +0,0 @@
|
||||||
package crypto
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto/sha256"
|
|
||||||
"golang.org/x/crypto/ripemd160"
|
|
||||||
)
|
|
||||||
|
|
||||||
func Sha256(bytes []byte) []byte {
|
|
||||||
hasher := sha256.New()
|
|
||||||
hasher.Write(bytes)
|
|
||||||
return hasher.Sum(nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
func Ripemd160(bytes []byte) []byte {
|
|
||||||
hasher := ripemd160.New()
|
|
||||||
hasher.Write(bytes)
|
|
||||||
return hasher.Sum(nil)
|
|
||||||
}
|
|
|
@ -1,105 +0,0 @@
|
||||||
// Package hkdfchacha20poly1305 creates an AEAD using hkdf, chacha20, and poly1305
|
|
||||||
// When sealing and opening, the hkdf is used to obtain the nonce and subkey for
|
|
||||||
// chacha20. Other than the change for the how the subkey and nonce for chacha
|
|
||||||
// are obtained, this is the same as chacha20poly1305
|
|
||||||
package hkdfchacha20poly1305
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto/cipher"
|
|
||||||
"crypto/sha256"
|
|
||||||
"errors"
|
|
||||||
"io"
|
|
||||||
|
|
||||||
"golang.org/x/crypto/chacha20poly1305"
|
|
||||||
"golang.org/x/crypto/hkdf"
|
|
||||||
)
|
|
||||||
|
|
||||||
type hkdfchacha20poly1305 struct {
|
|
||||||
key [KeySize]byte
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
|
||||||
// KeySize is the size of the key used by this AEAD, in bytes.
|
|
||||||
KeySize = 32
|
|
||||||
// NonceSize is the size of the nonce used with this AEAD, in bytes.
|
|
||||||
NonceSize = 24
|
|
||||||
// TagSize is the size added from poly1305
|
|
||||||
TagSize = 16
|
|
||||||
// MaxPlaintextSize is the max size that can be passed into a single call of Seal
|
|
||||||
MaxPlaintextSize = (1 << 38) - 64
|
|
||||||
// MaxCiphertextSize is the max size that can be passed into a single call of Open,
|
|
||||||
// this differs from plaintext size due to the tag
|
|
||||||
MaxCiphertextSize = (1 << 38) - 48
|
|
||||||
// HkdfInfo is the parameter used internally for Hkdf's info parameter.
|
|
||||||
HkdfInfo = "TENDERMINT_SECRET_CONNECTION_FRAME_KEY_DERIVE"
|
|
||||||
)
|
|
||||||
|
|
||||||
//New xChaChapoly1305 AEAD with 24 byte nonces
|
|
||||||
func New(key []byte) (cipher.AEAD, error) {
|
|
||||||
if len(key) != KeySize {
|
|
||||||
return nil, errors.New("chacha20poly1305: bad key length")
|
|
||||||
}
|
|
||||||
ret := new(hkdfchacha20poly1305)
|
|
||||||
copy(ret.key[:], key)
|
|
||||||
return ret, nil
|
|
||||||
|
|
||||||
}
|
|
||||||
func (c *hkdfchacha20poly1305) NonceSize() int {
|
|
||||||
return NonceSize
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *hkdfchacha20poly1305) Overhead() int {
|
|
||||||
return TagSize
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *hkdfchacha20poly1305) Seal(dst, nonce, plaintext, additionalData []byte) []byte {
|
|
||||||
if len(nonce) != NonceSize {
|
|
||||||
panic("hkdfchacha20poly1305: bad nonce length passed to Seal")
|
|
||||||
}
|
|
||||||
|
|
||||||
if uint64(len(plaintext)) > MaxPlaintextSize {
|
|
||||||
panic("hkdfchacha20poly1305: plaintext too large")
|
|
||||||
}
|
|
||||||
|
|
||||||
subKey, chachaNonce := getSubkeyAndChachaNonceFromHkdf(&c.key, &nonce)
|
|
||||||
|
|
||||||
aead, err := chacha20poly1305.New(subKey[:])
|
|
||||||
if err != nil {
|
|
||||||
panic("hkdfchacha20poly1305: failed to initialize chacha20poly1305")
|
|
||||||
}
|
|
||||||
|
|
||||||
return aead.Seal(dst, chachaNonce[:], plaintext, additionalData)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *hkdfchacha20poly1305) Open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) {
|
|
||||||
if len(nonce) != NonceSize {
|
|
||||||
return nil, errors.New("hkdfchacha20poly1305: bad nonce length passed to Open")
|
|
||||||
}
|
|
||||||
if uint64(len(ciphertext)) > MaxCiphertextSize {
|
|
||||||
return nil, errors.New("hkdfchacha20poly1305: ciphertext too large")
|
|
||||||
}
|
|
||||||
|
|
||||||
subKey, chachaNonce := getSubkeyAndChachaNonceFromHkdf(&c.key, &nonce)
|
|
||||||
|
|
||||||
aead, err := chacha20poly1305.New(subKey[:])
|
|
||||||
if err != nil {
|
|
||||||
panic("hkdfchacha20poly1305: failed to initialize chacha20poly1305")
|
|
||||||
}
|
|
||||||
|
|
||||||
return aead.Open(dst, chachaNonce[:], ciphertext, additionalData)
|
|
||||||
}
|
|
||||||
|
|
||||||
func getSubkeyAndChachaNonceFromHkdf(cKey *[32]byte, nonce *[]byte) (
|
|
||||||
subKey [KeySize]byte, chachaNonce [chacha20poly1305.NonceSize]byte) {
|
|
||||||
hash := sha256.New
|
|
||||||
hkdf := hkdf.New(hash, (*cKey)[:], *nonce, []byte(HkdfInfo))
|
|
||||||
_, err := io.ReadFull(hkdf, subKey[:])
|
|
||||||
if err != nil {
|
|
||||||
panic("hkdfchacha20poly1305: failed to read subkey from hkdf")
|
|
||||||
}
|
|
||||||
_, err = io.ReadFull(hkdf, chachaNonce[:])
|
|
||||||
if err != nil {
|
|
||||||
panic("hkdfchacha20poly1305: failed to read chachaNonce from hkdf")
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
|
@ -1,139 +0,0 @@
|
||||||
package hkdfchacha20poly1305
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
cr "crypto/rand"
|
|
||||||
"encoding/hex"
|
|
||||||
mr "math/rand"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Test that a test vector we generated is valid. (Ensures backwards
|
|
||||||
// compatability)
|
|
||||||
func TestVector(t *testing.T) {
|
|
||||||
key, _ := hex.DecodeString("56f8de45d3c294c7675bcaf457bdd4b71c380b9b2408ce9412b348d0f08b69ee")
|
|
||||||
aead, err := New(key[:])
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
cts := []string{"e20a8bf42c535ac30125cfc52031577f0b",
|
|
||||||
"657695b37ba30f67b25860d90a6f1d00d8",
|
|
||||||
"e9aa6f3b7f625d957fd50f05bcdf20d014",
|
|
||||||
"8a00b3b5a6014e0d2033bebc5935086245",
|
|
||||||
"aadd74867b923879e6866ea9e03c009039",
|
|
||||||
"fc59773c2c864ee3b4cc971876b3c7bed4",
|
|
||||||
"caec14e3a9a52ce1a2682c6737defa4752",
|
|
||||||
"0b89511ffe490d2049d6950494ee51f919",
|
|
||||||
"7de854ea71f43ca35167a07566c769083d",
|
|
||||||
"cd477327f4ea4765c71e311c5fec1edbfb"}
|
|
||||||
|
|
||||||
for i := 0; i < 10; i++ {
|
|
||||||
ct, _ := hex.DecodeString(cts[i])
|
|
||||||
|
|
||||||
byteArr := []byte{byte(i)}
|
|
||||||
nonce := make([]byte, 24, 24)
|
|
||||||
nonce[0] = byteArr[0]
|
|
||||||
|
|
||||||
plaintext, err := aead.Open(nil, nonce, ct, byteArr)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("%dth Open failed", i)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
assert.Equal(t, byteArr, plaintext)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// The following test is taken from
|
|
||||||
// https://github.com/golang/crypto/blob/master/chacha20poly1305/chacha20poly1305_test.go#L69
|
|
||||||
// It requires the below copyright notice, where "this source code" refers to the following function.
|
|
||||||
// Copyright 2016 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found at the bottom of this file.
|
|
||||||
func TestRandom(t *testing.T) {
|
|
||||||
// Some random tests to verify Open(Seal) == Plaintext
|
|
||||||
for i := 0; i < 256; i++ {
|
|
||||||
var nonce [24]byte
|
|
||||||
var key [32]byte
|
|
||||||
|
|
||||||
al := mr.Intn(128)
|
|
||||||
pl := mr.Intn(16384)
|
|
||||||
ad := make([]byte, al)
|
|
||||||
plaintext := make([]byte, pl)
|
|
||||||
cr.Read(key[:])
|
|
||||||
cr.Read(nonce[:])
|
|
||||||
cr.Read(ad)
|
|
||||||
cr.Read(plaintext)
|
|
||||||
|
|
||||||
aead, err := New(key[:])
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
ct := aead.Seal(nil, nonce[:], plaintext, ad)
|
|
||||||
|
|
||||||
plaintext2, err := aead.Open(nil, nonce[:], ct, ad)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Random #%d: Open failed", i)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if !bytes.Equal(plaintext, plaintext2) {
|
|
||||||
t.Errorf("Random #%d: plaintext's don't match: got %x vs %x", i, plaintext2, plaintext)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(ad) > 0 {
|
|
||||||
alterAdIdx := mr.Intn(len(ad))
|
|
||||||
ad[alterAdIdx] ^= 0x80
|
|
||||||
if _, err := aead.Open(nil, nonce[:], ct, ad); err == nil {
|
|
||||||
t.Errorf("Random #%d: Open was successful after altering additional data", i)
|
|
||||||
}
|
|
||||||
ad[alterAdIdx] ^= 0x80
|
|
||||||
}
|
|
||||||
|
|
||||||
alterNonceIdx := mr.Intn(aead.NonceSize())
|
|
||||||
nonce[alterNonceIdx] ^= 0x80
|
|
||||||
if _, err := aead.Open(nil, nonce[:], ct, ad); err == nil {
|
|
||||||
t.Errorf("Random #%d: Open was successful after altering nonce", i)
|
|
||||||
}
|
|
||||||
nonce[alterNonceIdx] ^= 0x80
|
|
||||||
|
|
||||||
alterCtIdx := mr.Intn(len(ct))
|
|
||||||
ct[alterCtIdx] ^= 0x80
|
|
||||||
if _, err := aead.Open(nil, nonce[:], ct, ad); err == nil {
|
|
||||||
t.Errorf("Random #%d: Open was successful after altering ciphertext", i)
|
|
||||||
}
|
|
||||||
ct[alterCtIdx] ^= 0x80
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// AFOREMENTIONED LICENCE
|
|
||||||
// Copyright (c) 2009 The Go Authors. All rights reserved.
|
|
||||||
//
|
|
||||||
// Redistribution and use in source and binary forms, with or without
|
|
||||||
// modification, are permitted provided that the following conditions are
|
|
||||||
// met:
|
|
||||||
//
|
|
||||||
// * Redistributions of source code must retain the above copyright
|
|
||||||
// notice, this list of conditions and the following disclaimer.
|
|
||||||
// * Redistributions in binary form must reproduce the above
|
|
||||||
// copyright notice, this list of conditions and the following disclaimer
|
|
||||||
// in the documentation and/or other materials provided with the
|
|
||||||
// distribution.
|
|
||||||
// * Neither the name of Google Inc. nor the names of its
|
|
||||||
// contributors may be used to endorse or promote products derived from
|
|
||||||
// this software without specific prior written permission.
|
|
||||||
//
|
|
||||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
||||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
||||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
||||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
||||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
||||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
||||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
||||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
||||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
||||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
@ -1,4 +0,0 @@
|
||||||
## Simple Merkle Tree
|
|
||||||
|
|
||||||
For smaller static data structures that don't require immutable snapshots or mutability;
|
|
||||||
for instance the transactions and validation signatures of a block can be hashed using this simple merkle tree logic.
|
|
|
@ -1,31 +0,0 @@
|
||||||
/*
|
|
||||||
Package merkle computes a deterministic minimal height Merkle tree hash.
|
|
||||||
If the number of items is not a power of two, some leaves
|
|
||||||
will be at different levels. Tries to keep both sides of
|
|
||||||
the tree the same size, but the left may be one greater.
|
|
||||||
|
|
||||||
Use this for short deterministic trees, such as the validator list.
|
|
||||||
For larger datasets, use IAVLTree.
|
|
||||||
|
|
||||||
Be aware that the current implementation by itself does not prevent
|
|
||||||
second pre-image attacks. Hence, use this library with caution.
|
|
||||||
Otherwise you might run into similar issues as, e.g., in early Bitcoin:
|
|
||||||
https://bitcointalk.org/?topic=102395
|
|
||||||
|
|
||||||
*
|
|
||||||
/ \
|
|
||||||
/ \
|
|
||||||
/ \
|
|
||||||
/ \
|
|
||||||
* *
|
|
||||||
/ \ / \
|
|
||||||
/ \ / \
|
|
||||||
/ \ / \
|
|
||||||
* * * h6
|
|
||||||
/ \ / \ / \
|
|
||||||
h0 h1 h2 h3 h4 h5
|
|
||||||
|
|
||||||
TODO(ismail): add 2nd pre-image protection or clarify further on how we use this and why this secure.
|
|
||||||
|
|
||||||
*/
|
|
||||||
package merkle
|
|
|
@ -1,88 +0,0 @@
|
||||||
package merkle
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/tendermint/go-crypto/tmhash"
|
|
||||||
cmn "github.com/tendermint/tmlibs/common"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Merkle tree from a map.
|
|
||||||
// Leaves are `hash(key) | hash(value)`.
|
|
||||||
// Leaves are sorted before Merkle hashing.
|
|
||||||
type simpleMap struct {
|
|
||||||
kvs cmn.KVPairs
|
|
||||||
sorted bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func newSimpleMap() *simpleMap {
|
|
||||||
return &simpleMap{
|
|
||||||
kvs: nil,
|
|
||||||
sorted: false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set hashes the key and value and appends it to the kv pairs.
|
|
||||||
func (sm *simpleMap) Set(key string, value Hasher) {
|
|
||||||
sm.sorted = false
|
|
||||||
|
|
||||||
// The value is hashed, so you can
|
|
||||||
// check for equality with a cached value (say)
|
|
||||||
// and make a determination to fetch or not.
|
|
||||||
vhash := value.Hash()
|
|
||||||
|
|
||||||
sm.kvs = append(sm.kvs, cmn.KVPair{
|
|
||||||
Key: []byte(key),
|
|
||||||
Value: vhash,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hash Merkle root hash of items sorted by key
|
|
||||||
// (UNSTABLE: and by value too if duplicate key).
|
|
||||||
func (sm *simpleMap) Hash() []byte {
|
|
||||||
sm.Sort()
|
|
||||||
return hashKVPairs(sm.kvs)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sm *simpleMap) Sort() {
|
|
||||||
if sm.sorted {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
sm.kvs.Sort()
|
|
||||||
sm.sorted = true
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns a copy of sorted KVPairs.
|
|
||||||
// NOTE these contain the hashed key and value.
|
|
||||||
func (sm *simpleMap) KVPairs() cmn.KVPairs {
|
|
||||||
sm.Sort()
|
|
||||||
kvs := make(cmn.KVPairs, len(sm.kvs))
|
|
||||||
copy(kvs, sm.kvs)
|
|
||||||
return kvs
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------
|
|
||||||
|
|
||||||
// A local extension to KVPair that can be hashed.
|
|
||||||
// Key and value are length prefixed and concatenated,
|
|
||||||
// then hashed.
|
|
||||||
type KVPair cmn.KVPair
|
|
||||||
|
|
||||||
func (kv KVPair) Hash() []byte {
|
|
||||||
hasher := tmhash.New()
|
|
||||||
err := encodeByteSlice(hasher, kv.Key)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
err = encodeByteSlice(hasher, kv.Value)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
return hasher.Sum(nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
func hashKVPairs(kvs cmn.KVPairs) []byte {
|
|
||||||
kvsH := make([]Hasher, len(kvs))
|
|
||||||
for i, kvp := range kvs {
|
|
||||||
kvsH[i] = KVPair(kvp)
|
|
||||||
}
|
|
||||||
return SimpleHashFromHashers(kvsH)
|
|
||||||
}
|
|
|
@ -1,54 +0,0 @@
|
||||||
package merkle
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"github.com/tendermint/go-crypto/tmhash"
|
|
||||||
)
|
|
||||||
|
|
||||||
type strHasher string
|
|
||||||
|
|
||||||
func (str strHasher) Hash() []byte {
|
|
||||||
return tmhash.Sum([]byte(str))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSimpleMap(t *testing.T) {
|
|
||||||
{
|
|
||||||
db := newSimpleMap()
|
|
||||||
db.Set("key1", strHasher("value1"))
|
|
||||||
assert.Equal(t, "fa9bc106ffd932d919bee935ceb6cf2b3dd72d8f", fmt.Sprintf("%x", db.Hash()), "Hash didn't match")
|
|
||||||
}
|
|
||||||
{
|
|
||||||
db := newSimpleMap()
|
|
||||||
db.Set("key1", strHasher("value2"))
|
|
||||||
assert.Equal(t, "e00e7dcfe54e9fafef5111e813a587f01ba9c3e8", fmt.Sprintf("%x", db.Hash()), "Hash didn't match")
|
|
||||||
}
|
|
||||||
{
|
|
||||||
db := newSimpleMap()
|
|
||||||
db.Set("key1", strHasher("value1"))
|
|
||||||
db.Set("key2", strHasher("value2"))
|
|
||||||
assert.Equal(t, "eff12d1c703a1022ab509287c0f196130123d786", fmt.Sprintf("%x", db.Hash()), "Hash didn't match")
|
|
||||||
}
|
|
||||||
{
|
|
||||||
db := newSimpleMap()
|
|
||||||
db.Set("key2", strHasher("value2")) // NOTE: out of order
|
|
||||||
db.Set("key1", strHasher("value1"))
|
|
||||||
assert.Equal(t, "eff12d1c703a1022ab509287c0f196130123d786", fmt.Sprintf("%x", db.Hash()), "Hash didn't match")
|
|
||||||
}
|
|
||||||
{
|
|
||||||
db := newSimpleMap()
|
|
||||||
db.Set("key1", strHasher("value1"))
|
|
||||||
db.Set("key2", strHasher("value2"))
|
|
||||||
db.Set("key3", strHasher("value3"))
|
|
||||||
assert.Equal(t, "b2c62a277c08dbd2ad73ca53cd1d6bfdf5830d26", fmt.Sprintf("%x", db.Hash()), "Hash didn't match")
|
|
||||||
}
|
|
||||||
{
|
|
||||||
db := newSimpleMap()
|
|
||||||
db.Set("key2", strHasher("value2")) // NOTE: out of order
|
|
||||||
db.Set("key1", strHasher("value1"))
|
|
||||||
db.Set("key3", strHasher("value3"))
|
|
||||||
assert.Equal(t, "b2c62a277c08dbd2ad73ca53cd1d6bfdf5830d26", fmt.Sprintf("%x", db.Hash()), "Hash didn't match")
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,160 +0,0 @@
|
||||||
package merkle
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"fmt"
|
|
||||||
)
|
|
||||||
|
|
||||||
// SimpleProof represents a simple merkle proof.
|
|
||||||
type SimpleProof struct {
|
|
||||||
Aunts [][]byte `json:"aunts"` // Hashes from leaf's sibling to a root's child.
|
|
||||||
}
|
|
||||||
|
|
||||||
// SimpleProofsFromHashers computes inclusion proof for given items.
|
|
||||||
// proofs[0] is the proof for items[0].
|
|
||||||
func SimpleProofsFromHashers(items []Hasher) (rootHash []byte, proofs []*SimpleProof) {
|
|
||||||
trails, rootSPN := trailsFromHashers(items)
|
|
||||||
rootHash = rootSPN.Hash
|
|
||||||
proofs = make([]*SimpleProof, len(items))
|
|
||||||
for i, trail := range trails {
|
|
||||||
proofs[i] = &SimpleProof{
|
|
||||||
Aunts: trail.FlattenAunts(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// SimpleProofsFromMap generates proofs from a map. The keys/values of the map will be used as the keys/values
|
|
||||||
// in the underlying key-value pairs.
|
|
||||||
// The keys are sorted before the proofs are computed.
|
|
||||||
func SimpleProofsFromMap(m map[string]Hasher) (rootHash []byte, proofs map[string]*SimpleProof, keys []string) {
|
|
||||||
sm := newSimpleMap()
|
|
||||||
for k, v := range m {
|
|
||||||
sm.Set(k, v)
|
|
||||||
}
|
|
||||||
sm.Sort()
|
|
||||||
kvs := sm.kvs
|
|
||||||
kvsH := make([]Hasher, 0, len(kvs))
|
|
||||||
for _, kvp := range kvs {
|
|
||||||
kvsH = append(kvsH, KVPair(kvp))
|
|
||||||
}
|
|
||||||
|
|
||||||
rootHash, proofList := SimpleProofsFromHashers(kvsH)
|
|
||||||
proofs = make(map[string]*SimpleProof)
|
|
||||||
keys = make([]string, len(proofList))
|
|
||||||
for i, kvp := range kvs {
|
|
||||||
proofs[string(kvp.Key)] = proofList[i]
|
|
||||||
keys[i] = string(kvp.Key)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verify that leafHash is a leaf hash of the simple-merkle-tree
|
|
||||||
// which hashes to rootHash.
|
|
||||||
func (sp *SimpleProof) Verify(index int, total int, leafHash []byte, rootHash []byte) bool {
|
|
||||||
computedHash := computeHashFromAunts(index, total, leafHash, sp.Aunts)
|
|
||||||
return computedHash != nil && bytes.Equal(computedHash, rootHash)
|
|
||||||
}
|
|
||||||
|
|
||||||
// String implements the stringer interface for SimpleProof.
|
|
||||||
// It is a wrapper around StringIndented.
|
|
||||||
func (sp *SimpleProof) String() string {
|
|
||||||
return sp.StringIndented("")
|
|
||||||
}
|
|
||||||
|
|
||||||
// StringIndented generates a canonical string representation of a SimpleProof.
|
|
||||||
func (sp *SimpleProof) StringIndented(indent string) string {
|
|
||||||
return fmt.Sprintf(`SimpleProof{
|
|
||||||
%s Aunts: %X
|
|
||||||
%s}`,
|
|
||||||
indent, sp.Aunts,
|
|
||||||
indent)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use the leafHash and innerHashes to get the root merkle hash.
|
|
||||||
// If the length of the innerHashes slice isn't exactly correct, the result is nil.
|
|
||||||
// Recursive impl.
|
|
||||||
func computeHashFromAunts(index int, total int, leafHash []byte, innerHashes [][]byte) []byte {
|
|
||||||
if index >= total || index < 0 || total <= 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
switch total {
|
|
||||||
case 0:
|
|
||||||
panic("Cannot call computeHashFromAunts() with 0 total")
|
|
||||||
case 1:
|
|
||||||
if len(innerHashes) != 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return leafHash
|
|
||||||
default:
|
|
||||||
if len(innerHashes) == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
numLeft := (total + 1) / 2
|
|
||||||
if index < numLeft {
|
|
||||||
leftHash := computeHashFromAunts(index, numLeft, leafHash, innerHashes[:len(innerHashes)-1])
|
|
||||||
if leftHash == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return SimpleHashFromTwoHashes(leftHash, innerHashes[len(innerHashes)-1])
|
|
||||||
}
|
|
||||||
rightHash := computeHashFromAunts(index-numLeft, total-numLeft, leafHash, innerHashes[:len(innerHashes)-1])
|
|
||||||
if rightHash == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return SimpleHashFromTwoHashes(innerHashes[len(innerHashes)-1], rightHash)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// SimpleProofNode is a helper structure to construct merkle proof.
|
|
||||||
// The node and the tree is thrown away afterwards.
|
|
||||||
// Exactly one of node.Left and node.Right is nil, unless node is the root, in which case both are nil.
|
|
||||||
// node.Parent.Hash = hash(node.Hash, node.Right.Hash) or
|
|
||||||
// hash(node.Left.Hash, node.Hash), depending on whether node is a left/right child.
|
|
||||||
type SimpleProofNode struct {
|
|
||||||
Hash []byte
|
|
||||||
Parent *SimpleProofNode
|
|
||||||
Left *SimpleProofNode // Left sibling (only one of Left,Right is set)
|
|
||||||
Right *SimpleProofNode // Right sibling (only one of Left,Right is set)
|
|
||||||
}
|
|
||||||
|
|
||||||
// FlattenAunts will return the inner hashes for the item corresponding to the leaf,
|
|
||||||
// starting from a leaf SimpleProofNode.
|
|
||||||
func (spn *SimpleProofNode) FlattenAunts() [][]byte {
|
|
||||||
// Nonrecursive impl.
|
|
||||||
innerHashes := [][]byte{}
|
|
||||||
for spn != nil {
|
|
||||||
if spn.Left != nil {
|
|
||||||
innerHashes = append(innerHashes, spn.Left.Hash)
|
|
||||||
} else if spn.Right != nil {
|
|
||||||
innerHashes = append(innerHashes, spn.Right.Hash)
|
|
||||||
} else {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
spn = spn.Parent
|
|
||||||
}
|
|
||||||
return innerHashes
|
|
||||||
}
|
|
||||||
|
|
||||||
// trails[0].Hash is the leaf hash for items[0].
|
|
||||||
// trails[i].Parent.Parent....Parent == root for all i.
|
|
||||||
func trailsFromHashers(items []Hasher) (trails []*SimpleProofNode, root *SimpleProofNode) {
|
|
||||||
// Recursive impl.
|
|
||||||
switch len(items) {
|
|
||||||
case 0:
|
|
||||||
return nil, nil
|
|
||||||
case 1:
|
|
||||||
trail := &SimpleProofNode{items[0].Hash(), nil, nil, nil}
|
|
||||||
return []*SimpleProofNode{trail}, trail
|
|
||||||
default:
|
|
||||||
lefts, leftRoot := trailsFromHashers(items[:(len(items)+1)/2])
|
|
||||||
rights, rightRoot := trailsFromHashers(items[(len(items)+1)/2:])
|
|
||||||
rootHash := SimpleHashFromTwoHashes(leftRoot.Hash, rightRoot.Hash)
|
|
||||||
root := &SimpleProofNode{rootHash, nil, nil, nil}
|
|
||||||
leftRoot.Parent = root
|
|
||||||
leftRoot.Right = rightRoot
|
|
||||||
rightRoot.Parent = root
|
|
||||||
rightRoot.Left = leftRoot
|
|
||||||
return append(lefts, rights...), root
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,58 +0,0 @@
|
||||||
package merkle
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/tendermint/go-crypto/tmhash"
|
|
||||||
)
|
|
||||||
|
|
||||||
// SimpleHashFromTwoHashes is the basic operation of the Merkle tree: Hash(left | right).
|
|
||||||
func SimpleHashFromTwoHashes(left, right []byte) []byte {
|
|
||||||
var hasher = tmhash.New()
|
|
||||||
err := encodeByteSlice(hasher, left)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
err = encodeByteSlice(hasher, right)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
return hasher.Sum(nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SimpleHashFromHashers computes a Merkle tree from items that can be hashed.
|
|
||||||
func SimpleHashFromHashers(items []Hasher) []byte {
|
|
||||||
hashes := make([][]byte, len(items))
|
|
||||||
for i, item := range items {
|
|
||||||
hash := item.Hash()
|
|
||||||
hashes[i] = hash
|
|
||||||
}
|
|
||||||
return simpleHashFromHashes(hashes)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SimpleHashFromMap computes a Merkle tree from sorted map.
|
|
||||||
// Like calling SimpleHashFromHashers with
|
|
||||||
// `item = []byte(Hash(key) | Hash(value))`,
|
|
||||||
// sorted by `item`.
|
|
||||||
func SimpleHashFromMap(m map[string]Hasher) []byte {
|
|
||||||
sm := newSimpleMap()
|
|
||||||
for k, v := range m {
|
|
||||||
sm.Set(k, v)
|
|
||||||
}
|
|
||||||
return sm.Hash()
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------
|
|
||||||
|
|
||||||
// Expects hashes!
|
|
||||||
func simpleHashFromHashes(hashes [][]byte) []byte {
|
|
||||||
// Recursive impl.
|
|
||||||
switch len(hashes) {
|
|
||||||
case 0:
|
|
||||||
return nil
|
|
||||||
case 1:
|
|
||||||
return hashes[0]
|
|
||||||
default:
|
|
||||||
left := simpleHashFromHashes(hashes[:(len(hashes)+1)/2])
|
|
||||||
right := simpleHashFromHashes(hashes[(len(hashes)+1)/2:])
|
|
||||||
return SimpleHashFromTwoHashes(left, right)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,88 +0,0 @@
|
||||||
package merkle
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
|
|
||||||
cmn "github.com/tendermint/tmlibs/common"
|
|
||||||
. "github.com/tendermint/tmlibs/test"
|
|
||||||
|
|
||||||
"testing"
|
|
||||||
"github.com/tendermint/go-crypto/tmhash"
|
|
||||||
)
|
|
||||||
|
|
||||||
type testItem []byte
|
|
||||||
|
|
||||||
func (tI testItem) Hash() []byte {
|
|
||||||
return []byte(tI)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSimpleProof(t *testing.T) {
|
|
||||||
|
|
||||||
total := 100
|
|
||||||
|
|
||||||
items := make([]Hasher, total)
|
|
||||||
for i := 0; i < total; i++ {
|
|
||||||
items[i] = testItem(cmn.RandBytes(tmhash.Size))
|
|
||||||
}
|
|
||||||
|
|
||||||
rootHash := SimpleHashFromHashers(items)
|
|
||||||
|
|
||||||
rootHash2, proofs := SimpleProofsFromHashers(items)
|
|
||||||
|
|
||||||
if !bytes.Equal(rootHash, rootHash2) {
|
|
||||||
t.Errorf("Unmatched root hashes: %X vs %X", rootHash, rootHash2)
|
|
||||||
}
|
|
||||||
|
|
||||||
// For each item, check the trail.
|
|
||||||
for i, item := range items {
|
|
||||||
itemHash := item.Hash()
|
|
||||||
proof := proofs[i]
|
|
||||||
|
|
||||||
// Verify success
|
|
||||||
ok := proof.Verify(i, total, itemHash, rootHash)
|
|
||||||
if !ok {
|
|
||||||
t.Errorf("Verification failed for index %v.", i)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wrong item index should make it fail
|
|
||||||
{
|
|
||||||
ok = proof.Verify((i+1)%total, total, itemHash, rootHash)
|
|
||||||
if ok {
|
|
||||||
t.Errorf("Expected verification to fail for wrong index %v.", i)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Trail too long should make it fail
|
|
||||||
origAunts := proof.Aunts
|
|
||||||
proof.Aunts = append(proof.Aunts, cmn.RandBytes(32))
|
|
||||||
{
|
|
||||||
ok = proof.Verify(i, total, itemHash, rootHash)
|
|
||||||
if ok {
|
|
||||||
t.Errorf("Expected verification to fail for wrong trail length.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
proof.Aunts = origAunts
|
|
||||||
|
|
||||||
// Trail too short should make it fail
|
|
||||||
proof.Aunts = proof.Aunts[0 : len(proof.Aunts)-1]
|
|
||||||
{
|
|
||||||
ok = proof.Verify(i, total, itemHash, rootHash)
|
|
||||||
if ok {
|
|
||||||
t.Errorf("Expected verification to fail for wrong trail length.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
proof.Aunts = origAunts
|
|
||||||
|
|
||||||
// Mutating the itemHash should make it fail.
|
|
||||||
ok = proof.Verify(i, total, MutateByteSlice(itemHash), rootHash)
|
|
||||||
if ok {
|
|
||||||
t.Errorf("Expected verification to fail for mutated leaf hash")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Mutating the rootHash should make it fail.
|
|
||||||
ok = proof.Verify(i, total, itemHash, MutateByteSlice(rootHash))
|
|
||||||
if ok {
|
|
||||||
t.Errorf("Expected verification to fail for mutated root hash")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,38 +0,0 @@
|
||||||
package merkle
|
|
||||||
|
|
||||||
import (
|
|
||||||
"io"
|
|
||||||
|
|
||||||
amino "github.com/tendermint/go-amino"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Tree is a Merkle tree interface.
|
|
||||||
type Tree interface {
|
|
||||||
Size() (size int)
|
|
||||||
Height() (height int8)
|
|
||||||
Has(key []byte) (has bool)
|
|
||||||
Proof(key []byte) (value []byte, proof []byte, exists bool) // TODO make it return an index
|
|
||||||
Get(key []byte) (index int, value []byte, exists bool)
|
|
||||||
GetByIndex(index int) (key []byte, value []byte)
|
|
||||||
Set(key []byte, value []byte) (updated bool)
|
|
||||||
Remove(key []byte) (value []byte, removed bool)
|
|
||||||
HashWithCount() (hash []byte, count int)
|
|
||||||
Hash() (hash []byte)
|
|
||||||
Save() (hash []byte)
|
|
||||||
Load(hash []byte)
|
|
||||||
Copy() Tree
|
|
||||||
Iterate(func(key []byte, value []byte) (stop bool)) (stopped bool)
|
|
||||||
IterateRange(start []byte, end []byte, ascending bool, fx func(key []byte, value []byte) (stop bool)) (stopped bool)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hasher represents a hashable piece of data which can be hashed in the Tree.
|
|
||||||
type Hasher interface {
|
|
||||||
Hash() []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------
|
|
||||||
|
|
||||||
// Uvarint length prefixed byteslice
|
|
||||||
func encodeByteSlice(w io.Writer, bz []byte) (err error) {
|
|
||||||
return amino.EncodeByteSlice(w, bz)
|
|
||||||
}
|
|
164
priv_key.go
164
priv_key.go
|
@ -1,164 +0,0 @@
|
||||||
package crypto
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto/subtle"
|
|
||||||
|
|
||||||
secp256k1 "github.com/btcsuite/btcd/btcec"
|
|
||||||
"github.com/tendermint/ed25519"
|
|
||||||
"github.com/tendermint/ed25519/extra25519"
|
|
||||||
)
|
|
||||||
|
|
||||||
func PrivKeyFromBytes(privKeyBytes []byte) (privKey PrivKey, err error) {
|
|
||||||
err = cdc.UnmarshalBinaryBare(privKeyBytes, &privKey)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------
|
|
||||||
|
|
||||||
type PrivKey interface {
|
|
||||||
Bytes() []byte
|
|
||||||
Sign(msg []byte) (Signature, error)
|
|
||||||
PubKey() PubKey
|
|
||||||
Equals(PrivKey) bool
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
|
|
||||||
var _ PrivKey = PrivKeyEd25519{}
|
|
||||||
|
|
||||||
// Implements PrivKey
|
|
||||||
type PrivKeyEd25519 [64]byte
|
|
||||||
|
|
||||||
func (privKey PrivKeyEd25519) Bytes() []byte {
|
|
||||||
return cdc.MustMarshalBinaryBare(privKey)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (privKey PrivKeyEd25519) Sign(msg []byte) (Signature, error) {
|
|
||||||
privKeyBytes := [64]byte(privKey)
|
|
||||||
signatureBytes := ed25519.Sign(&privKeyBytes, msg)
|
|
||||||
return SignatureEd25519(*signatureBytes), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (privKey PrivKeyEd25519) PubKey() PubKey {
|
|
||||||
privKeyBytes := [64]byte(privKey)
|
|
||||||
pubBytes := *ed25519.MakePublicKey(&privKeyBytes)
|
|
||||||
return PubKeyEd25519(pubBytes)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Equals - you probably don't need to use this.
|
|
||||||
// Runs in constant time based on length of the keys.
|
|
||||||
func (privKey PrivKeyEd25519) Equals(other PrivKey) bool {
|
|
||||||
if otherEd, ok := other.(PrivKeyEd25519); ok {
|
|
||||||
return subtle.ConstantTimeCompare(privKey[:], otherEd[:]) == 1
|
|
||||||
} else {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (privKey PrivKeyEd25519) ToCurve25519() *[32]byte {
|
|
||||||
keyCurve25519 := new([32]byte)
|
|
||||||
privKeyBytes := [64]byte(privKey)
|
|
||||||
extra25519.PrivateKeyToCurve25519(keyCurve25519, &privKeyBytes)
|
|
||||||
return keyCurve25519
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deterministically generates new priv-key bytes from key.
|
|
||||||
func (privKey PrivKeyEd25519) Generate(index int) PrivKeyEd25519 {
|
|
||||||
bz, err := cdc.MarshalBinaryBare(struct {
|
|
||||||
PrivKey [64]byte
|
|
||||||
Index int
|
|
||||||
}{privKey, index})
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
newBytes := Sha256(bz)
|
|
||||||
newKey := new([64]byte)
|
|
||||||
copy(newKey[:32], newBytes)
|
|
||||||
ed25519.MakePublicKey(newKey)
|
|
||||||
return PrivKeyEd25519(*newKey)
|
|
||||||
}
|
|
||||||
|
|
||||||
func GenPrivKeyEd25519() PrivKeyEd25519 {
|
|
||||||
privKeyBytes := new([64]byte)
|
|
||||||
copy(privKeyBytes[:32], CRandBytes(32))
|
|
||||||
ed25519.MakePublicKey(privKeyBytes)
|
|
||||||
return PrivKeyEd25519(*privKeyBytes)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NOTE: secret should be the output of a KDF like bcrypt,
|
|
||||||
// if it's derived from user input.
|
|
||||||
func GenPrivKeyEd25519FromSecret(secret []byte) PrivKeyEd25519 {
|
|
||||||
privKey32 := Sha256(secret) // Not Ripemd160 because we want 32 bytes.
|
|
||||||
privKeyBytes := new([64]byte)
|
|
||||||
copy(privKeyBytes[:32], privKey32)
|
|
||||||
ed25519.MakePublicKey(privKeyBytes)
|
|
||||||
return PrivKeyEd25519(*privKeyBytes)
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
|
|
||||||
var _ PrivKey = PrivKeySecp256k1{}
|
|
||||||
|
|
||||||
// Implements PrivKey
|
|
||||||
type PrivKeySecp256k1 [32]byte
|
|
||||||
|
|
||||||
func (privKey PrivKeySecp256k1) Bytes() []byte {
|
|
||||||
return cdc.MustMarshalBinaryBare(privKey)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (privKey PrivKeySecp256k1) Sign(msg []byte) (Signature, error) {
|
|
||||||
priv__, _ := secp256k1.PrivKeyFromBytes(secp256k1.S256(), privKey[:])
|
|
||||||
sig__, err := priv__.Sign(Sha256(msg))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return SignatureSecp256k1(sig__.Serialize()), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (privKey PrivKeySecp256k1) PubKey() PubKey {
|
|
||||||
_, pub__ := secp256k1.PrivKeyFromBytes(secp256k1.S256(), privKey[:])
|
|
||||||
var pub PubKeySecp256k1
|
|
||||||
copy(pub[:], pub__.SerializeCompressed())
|
|
||||||
return pub
|
|
||||||
}
|
|
||||||
|
|
||||||
// Equals - you probably don't need to use this.
|
|
||||||
// Runs in constant time based on length of the keys.
|
|
||||||
func (privKey PrivKeySecp256k1) Equals(other PrivKey) bool {
|
|
||||||
if otherSecp, ok := other.(PrivKeySecp256k1); ok {
|
|
||||||
return subtle.ConstantTimeCompare(privKey[:], otherSecp[:]) == 1
|
|
||||||
} else {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
// Deterministically generates new priv-key bytes from key.
|
|
||||||
func (key PrivKeySecp256k1) Generate(index int) PrivKeySecp256k1 {
|
|
||||||
newBytes := cdc.BinarySha256(struct {
|
|
||||||
PrivKey [64]byte
|
|
||||||
Index int
|
|
||||||
}{key, index})
|
|
||||||
var newKey [64]byte
|
|
||||||
copy(newKey[:], newBytes)
|
|
||||||
return PrivKeySecp256k1(newKey)
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
func GenPrivKeySecp256k1() PrivKeySecp256k1 {
|
|
||||||
privKeyBytes := [32]byte{}
|
|
||||||
copy(privKeyBytes[:], CRandBytes(32))
|
|
||||||
priv, _ := secp256k1.PrivKeyFromBytes(secp256k1.S256(), privKeyBytes[:])
|
|
||||||
copy(privKeyBytes[:], priv.Serialize())
|
|
||||||
return PrivKeySecp256k1(privKeyBytes)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NOTE: secret should be the output of a KDF like bcrypt,
|
|
||||||
// if it's derived from user input.
|
|
||||||
func GenPrivKeySecp256k1FromSecret(secret []byte) PrivKeySecp256k1 {
|
|
||||||
privKey32 := Sha256(secret) // Not Ripemd160 because we want 32 bytes.
|
|
||||||
priv, _ := secp256k1.PrivKeyFromBytes(secp256k1.S256(), privKey32)
|
|
||||||
privKeyBytes := [32]byte{}
|
|
||||||
copy(privKeyBytes[:], priv.Serialize())
|
|
||||||
return PrivKeySecp256k1(privKeyBytes)
|
|
||||||
}
|
|
|
@ -1,60 +0,0 @@
|
||||||
package crypto_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
crypto "github.com/tendermint/go-crypto"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestGeneratePrivKey(t *testing.T) {
|
|
||||||
testPriv := crypto.GenPrivKeyEd25519()
|
|
||||||
testGenerate := testPriv.Generate(1)
|
|
||||||
signBytes := []byte("something to sign")
|
|
||||||
pub := testGenerate.PubKey()
|
|
||||||
sig, err := testGenerate.Sign(signBytes)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.True(t, pub.VerifyBytes(signBytes, sig))
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
|
|
||||||
type BadKey struct {
|
|
||||||
PrivKeyEd25519
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestReadPrivKey(t *testing.T) {
|
|
||||||
assert, require := assert.New(t), require.New(t)
|
|
||||||
|
|
||||||
// garbage in, garbage out
|
|
||||||
garbage := []byte("hjgewugfbiewgofwgewr")
|
|
||||||
XXX This test wants to register BadKey globally to go-crypto,
|
|
||||||
but we don't want to support that.
|
|
||||||
_, err := PrivKeyFromBytes(garbage)
|
|
||||||
require.Error(err)
|
|
||||||
|
|
||||||
edKey := GenPrivKeyEd25519()
|
|
||||||
badKey := BadKey{edKey}
|
|
||||||
|
|
||||||
cases := []struct {
|
|
||||||
key PrivKey
|
|
||||||
valid bool
|
|
||||||
}{
|
|
||||||
{edKey, true},
|
|
||||||
{badKey, false},
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, tc := range cases {
|
|
||||||
data := tc.key.Bytes()
|
|
||||||
fmt.Println(">>>", data)
|
|
||||||
key, err := PrivKeyFromBytes(data)
|
|
||||||
fmt.Printf("!!! %#v\n", key, err)
|
|
||||||
if tc.valid {
|
|
||||||
assert.NoError(err, "%d", i)
|
|
||||||
assert.Equal(tc.key, key, "%d", i)
|
|
||||||
} else {
|
|
||||||
assert.Error(err, "%d: %#v", i, key)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
149
pub_key.go
149
pub_key.go
|
@ -1,149 +0,0 @@
|
||||||
package crypto
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"crypto/sha256"
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"golang.org/x/crypto/ripemd160"
|
|
||||||
|
|
||||||
secp256k1 "github.com/btcsuite/btcd/btcec"
|
|
||||||
|
|
||||||
"github.com/tendermint/ed25519"
|
|
||||||
"github.com/tendermint/ed25519/extra25519"
|
|
||||||
|
|
||||||
cmn "github.com/tendermint/tmlibs/common"
|
|
||||||
|
|
||||||
"github.com/tendermint/go-crypto/tmhash"
|
|
||||||
)
|
|
||||||
|
|
||||||
// An address is a []byte, but hex-encoded even in JSON.
|
|
||||||
// []byte leaves us the option to change the address length.
|
|
||||||
// Use an alias so Unmarshal methods (with ptr receivers) are available too.
|
|
||||||
type Address = cmn.HexBytes
|
|
||||||
|
|
||||||
func PubKeyFromBytes(pubKeyBytes []byte) (pubKey PubKey, err error) {
|
|
||||||
err = cdc.UnmarshalBinaryBare(pubKeyBytes, &pubKey)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------
|
|
||||||
|
|
||||||
type PubKey interface {
|
|
||||||
Address() Address
|
|
||||||
Bytes() []byte
|
|
||||||
VerifyBytes(msg []byte, sig Signature) bool
|
|
||||||
Equals(PubKey) bool
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
|
|
||||||
var _ PubKey = PubKeyEd25519{}
|
|
||||||
|
|
||||||
// Implements PubKeyInner
|
|
||||||
type PubKeyEd25519 [32]byte
|
|
||||||
|
|
||||||
// Address is the SHA256-20 of the raw pubkey bytes.
|
|
||||||
func (pubKey PubKeyEd25519) Address() Address {
|
|
||||||
return Address(tmhash.Sum(pubKey[:]))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (pubKey PubKeyEd25519) Bytes() []byte {
|
|
||||||
bz, err := cdc.MarshalBinaryBare(pubKey)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
return bz
|
|
||||||
}
|
|
||||||
|
|
||||||
func (pubKey PubKeyEd25519) VerifyBytes(msg []byte, sig_ Signature) bool {
|
|
||||||
// make sure we use the same algorithm to sign
|
|
||||||
sig, ok := sig_.(SignatureEd25519)
|
|
||||||
if !ok {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
pubKeyBytes := [32]byte(pubKey)
|
|
||||||
sigBytes := [64]byte(sig)
|
|
||||||
return ed25519.Verify(&pubKeyBytes, msg, &sigBytes)
|
|
||||||
}
|
|
||||||
|
|
||||||
// For use with golang/crypto/nacl/box
|
|
||||||
// If error, returns nil.
|
|
||||||
func (pubKey PubKeyEd25519) ToCurve25519() *[32]byte {
|
|
||||||
keyCurve25519, pubKeyBytes := new([32]byte), [32]byte(pubKey)
|
|
||||||
ok := extra25519.PublicKeyToCurve25519(keyCurve25519, &pubKeyBytes)
|
|
||||||
if !ok {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return keyCurve25519
|
|
||||||
}
|
|
||||||
|
|
||||||
func (pubKey PubKeyEd25519) String() string {
|
|
||||||
return fmt.Sprintf("PubKeyEd25519{%X}", pubKey[:])
|
|
||||||
}
|
|
||||||
|
|
||||||
func (pubKey PubKeyEd25519) Equals(other PubKey) bool {
|
|
||||||
if otherEd, ok := other.(PubKeyEd25519); ok {
|
|
||||||
return bytes.Equal(pubKey[:], otherEd[:])
|
|
||||||
} else {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
|
|
||||||
var _ PubKey = PubKeySecp256k1{}
|
|
||||||
|
|
||||||
// Implements PubKey.
|
|
||||||
// Compressed pubkey (just the x-cord),
|
|
||||||
// prefixed with 0x02 or 0x03, depending on the y-cord.
|
|
||||||
type PubKeySecp256k1 [33]byte
|
|
||||||
|
|
||||||
// Implements Bitcoin style addresses: RIPEMD160(SHA256(pubkey))
|
|
||||||
func (pubKey PubKeySecp256k1) Address() Address {
|
|
||||||
hasherSHA256 := sha256.New()
|
|
||||||
hasherSHA256.Write(pubKey[:]) // does not error
|
|
||||||
sha := hasherSHA256.Sum(nil)
|
|
||||||
|
|
||||||
hasherRIPEMD160 := ripemd160.New()
|
|
||||||
hasherRIPEMD160.Write(sha) // does not error
|
|
||||||
return Address(hasherRIPEMD160.Sum(nil))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (pubKey PubKeySecp256k1) Bytes() []byte {
|
|
||||||
bz, err := cdc.MarshalBinaryBare(pubKey)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
return bz
|
|
||||||
}
|
|
||||||
|
|
||||||
func (pubKey PubKeySecp256k1) VerifyBytes(msg []byte, sig_ Signature) bool {
|
|
||||||
// and assert same algorithm to sign and verify
|
|
||||||
sig, ok := sig_.(SignatureSecp256k1)
|
|
||||||
if !ok {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
pub__, err := secp256k1.ParsePubKey(pubKey[:], secp256k1.S256())
|
|
||||||
if err != nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
sig__, err := secp256k1.ParseDERSignature(sig[:], secp256k1.S256())
|
|
||||||
if err != nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return sig__.Verify(Sha256(msg), pub__)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (pubKey PubKeySecp256k1) String() string {
|
|
||||||
return fmt.Sprintf("PubKeySecp256k1{%X}", pubKey[:])
|
|
||||||
}
|
|
||||||
|
|
||||||
func (pubKey PubKeySecp256k1) Equals(other PubKey) bool {
|
|
||||||
if otherSecp, ok := other.(PubKeySecp256k1); ok {
|
|
||||||
return bytes.Equal(pubKey[:], otherSecp[:])
|
|
||||||
} else {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,50 +0,0 @@
|
||||||
package crypto
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/hex"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/btcsuite/btcutil/base58"
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
)
|
|
||||||
|
|
||||||
type keyData struct {
|
|
||||||
priv string
|
|
||||||
pub string
|
|
||||||
addr string
|
|
||||||
}
|
|
||||||
|
|
||||||
var secpDataTable = []keyData{
|
|
||||||
{
|
|
||||||
priv: "a96e62ed3955e65be32703f12d87b6b5cf26039ecfa948dc5107a495418e5330",
|
|
||||||
pub: "02950e1cdfcb133d6024109fd489f734eeb4502418e538c28481f22bce276f248c",
|
|
||||||
addr: "1CKZ9Nx4zgds8tU7nJHotKSDr4a9bYJCa3",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestPubKeySecp256k1Address(t *testing.T) {
|
|
||||||
for _, d := range secpDataTable {
|
|
||||||
privB, _ := hex.DecodeString(d.priv)
|
|
||||||
pubB, _ := hex.DecodeString(d.pub)
|
|
||||||
addrBbz, _, _ := base58.CheckDecode(d.addr)
|
|
||||||
addrB := Address(addrBbz)
|
|
||||||
|
|
||||||
var priv PrivKeySecp256k1
|
|
||||||
copy(priv[:], privB)
|
|
||||||
|
|
||||||
pubKey := priv.PubKey()
|
|
||||||
pubT, _ := pubKey.(PubKeySecp256k1)
|
|
||||||
pub := pubT[:]
|
|
||||||
addr := pubKey.Address()
|
|
||||||
|
|
||||||
assert.Equal(t, pub, pubB, "Expected pub keys to match")
|
|
||||||
assert.Equal(t, addr, addrB, "Expected addresses to match")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestPubKeyInvalidDataProperReturnsEmpty(t *testing.T) {
|
|
||||||
pk, err := PubKeyFromBytes([]byte("foo"))
|
|
||||||
require.NotNil(t, err, "expecting a non-nil error")
|
|
||||||
require.Nil(t, pk, "expecting an empty public key on error")
|
|
||||||
}
|
|
108
random.go
108
random.go
|
@ -1,108 +0,0 @@
|
||||||
package crypto
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto/aes"
|
|
||||||
"crypto/cipher"
|
|
||||||
crand "crypto/rand"
|
|
||||||
"crypto/sha256"
|
|
||||||
"encoding/hex"
|
|
||||||
"io"
|
|
||||||
"sync"
|
|
||||||
|
|
||||||
. "github.com/tendermint/tmlibs/common"
|
|
||||||
)
|
|
||||||
|
|
||||||
var gRandInfo *randInfo
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
gRandInfo = &randInfo{}
|
|
||||||
gRandInfo.MixEntropy(randBytes(32)) // Init
|
|
||||||
}
|
|
||||||
|
|
||||||
// Mix additional bytes of randomness, e.g. from hardware, user-input, etc.
|
|
||||||
// It is OK to call it multiple times. It does not diminish security.
|
|
||||||
func MixEntropy(seedBytes []byte) {
|
|
||||||
gRandInfo.MixEntropy(seedBytes)
|
|
||||||
}
|
|
||||||
|
|
||||||
// This only uses the OS's randomness
|
|
||||||
func randBytes(numBytes int) []byte {
|
|
||||||
b := make([]byte, numBytes)
|
|
||||||
_, err := crand.Read(b)
|
|
||||||
if err != nil {
|
|
||||||
PanicCrisis(err)
|
|
||||||
}
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
|
|
||||||
// This uses the OS and the Seed(s).
|
|
||||||
func CRandBytes(numBytes int) []byte {
|
|
||||||
b := make([]byte, numBytes)
|
|
||||||
_, err := gRandInfo.Read(b)
|
|
||||||
if err != nil {
|
|
||||||
PanicCrisis(err)
|
|
||||||
}
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
|
|
||||||
// CRandHex returns a hex encoded string that's floor(numDigits/2) * 2 long.
|
|
||||||
//
|
|
||||||
// Note: CRandHex(24) gives 96 bits of randomness that
|
|
||||||
// are usually strong enough for most purposes.
|
|
||||||
func CRandHex(numDigits int) string {
|
|
||||||
return hex.EncodeToString(CRandBytes(numDigits / 2))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns a crand.Reader mixed with user-supplied entropy
|
|
||||||
func CReader() io.Reader {
|
|
||||||
return gRandInfo
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
type randInfo struct {
|
|
||||||
mtx sync.Mutex
|
|
||||||
seedBytes [32]byte
|
|
||||||
cipherAES256 cipher.Block
|
|
||||||
streamAES256 cipher.Stream
|
|
||||||
reader io.Reader
|
|
||||||
}
|
|
||||||
|
|
||||||
// You can call this as many times as you'd like.
|
|
||||||
// XXX TODO review
|
|
||||||
func (ri *randInfo) MixEntropy(seedBytes []byte) {
|
|
||||||
ri.mtx.Lock()
|
|
||||||
defer ri.mtx.Unlock()
|
|
||||||
// Make new ri.seedBytes using passed seedBytes and current ri.seedBytes:
|
|
||||||
// ri.seedBytes = sha256( seedBytes || ri.seedBytes )
|
|
||||||
h := sha256.New()
|
|
||||||
h.Write(seedBytes)
|
|
||||||
h.Write(ri.seedBytes[:])
|
|
||||||
hashBytes := h.Sum(nil)
|
|
||||||
hashBytes32 := [32]byte{}
|
|
||||||
copy(hashBytes32[:], hashBytes)
|
|
||||||
ri.seedBytes = xorBytes32(ri.seedBytes, hashBytes32)
|
|
||||||
// Create new cipher.Block
|
|
||||||
var err error
|
|
||||||
ri.cipherAES256, err = aes.NewCipher(ri.seedBytes[:])
|
|
||||||
if err != nil {
|
|
||||||
PanicSanity("Error creating AES256 cipher: " + err.Error())
|
|
||||||
}
|
|
||||||
// Create new stream
|
|
||||||
ri.streamAES256 = cipher.NewCTR(ri.cipherAES256, randBytes(aes.BlockSize))
|
|
||||||
// Create new reader
|
|
||||||
ri.reader = &cipher.StreamReader{S: ri.streamAES256, R: crand.Reader}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ri *randInfo) Read(b []byte) (n int, err error) {
|
|
||||||
ri.mtx.Lock()
|
|
||||||
defer ri.mtx.Unlock()
|
|
||||||
return ri.reader.Read(b)
|
|
||||||
}
|
|
||||||
|
|
||||||
func xorBytes32(bytesA [32]byte, bytesB [32]byte) (res [32]byte) {
|
|
||||||
for i, b := range bytesA {
|
|
||||||
res[i] = b ^ bytesB[i]
|
|
||||||
}
|
|
||||||
return res
|
|
||||||
}
|
|
88
signature.go
88
signature.go
|
@ -1,88 +0,0 @@
|
||||||
package crypto
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"crypto/subtle"
|
|
||||||
|
|
||||||
. "github.com/tendermint/tmlibs/common"
|
|
||||||
)
|
|
||||||
|
|
||||||
func SignatureFromBytes(pubKeyBytes []byte) (pubKey Signature, err error) {
|
|
||||||
err = cdc.UnmarshalBinaryBare(pubKeyBytes, &pubKey)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------
|
|
||||||
|
|
||||||
type Signature interface {
|
|
||||||
Bytes() []byte
|
|
||||||
IsZero() bool
|
|
||||||
Equals(Signature) bool
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
|
|
||||||
var _ Signature = SignatureEd25519{}
|
|
||||||
|
|
||||||
// Implements Signature
|
|
||||||
type SignatureEd25519 [64]byte
|
|
||||||
|
|
||||||
func (sig SignatureEd25519) Bytes() []byte {
|
|
||||||
bz, err := cdc.MarshalBinaryBare(sig)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
return bz
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sig SignatureEd25519) IsZero() bool { return len(sig) == 0 }
|
|
||||||
|
|
||||||
func (sig SignatureEd25519) String() string { return fmt.Sprintf("/%X.../", Fingerprint(sig[:])) }
|
|
||||||
|
|
||||||
func (sig SignatureEd25519) Equals(other Signature) bool {
|
|
||||||
if otherEd, ok := other.(SignatureEd25519); ok {
|
|
||||||
return subtle.ConstantTimeCompare(sig[:], otherEd[:]) == 1
|
|
||||||
} else {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func SignatureEd25519FromBytes(data []byte) Signature {
|
|
||||||
var sig SignatureEd25519
|
|
||||||
copy(sig[:], data)
|
|
||||||
return sig
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
|
||||||
|
|
||||||
var _ Signature = SignatureSecp256k1{}
|
|
||||||
|
|
||||||
// Implements Signature
|
|
||||||
type SignatureSecp256k1 []byte
|
|
||||||
|
|
||||||
func (sig SignatureSecp256k1) Bytes() []byte {
|
|
||||||
bz, err := cdc.MarshalBinaryBare(sig)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
return bz
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sig SignatureSecp256k1) IsZero() bool { return len(sig) == 0 }
|
|
||||||
|
|
||||||
func (sig SignatureSecp256k1) String() string { return fmt.Sprintf("/%X.../", Fingerprint(sig[:])) }
|
|
||||||
|
|
||||||
func (sig SignatureSecp256k1) Equals(other Signature) bool {
|
|
||||||
if otherSecp, ok := other.(SignatureSecp256k1); ok {
|
|
||||||
return subtle.ConstantTimeCompare(sig[:], otherSecp[:]) == 1
|
|
||||||
} else {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func SignatureSecp256k1FromBytes(data []byte) Signature {
|
|
||||||
sig := make(SignatureSecp256k1, len(data))
|
|
||||||
copy(sig[:], data)
|
|
||||||
return sig
|
|
||||||
}
|
|
|
@ -1,46 +0,0 @@
|
||||||
package crypto
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestSignAndValidateEd25519(t *testing.T) {
|
|
||||||
|
|
||||||
privKey := GenPrivKeyEd25519()
|
|
||||||
pubKey := privKey.PubKey()
|
|
||||||
|
|
||||||
msg := CRandBytes(128)
|
|
||||||
sig, err := privKey.Sign(msg)
|
|
||||||
require.Nil(t, err)
|
|
||||||
|
|
||||||
// Test the signature
|
|
||||||
assert.True(t, pubKey.VerifyBytes(msg, sig))
|
|
||||||
|
|
||||||
// Mutate the signature, just one bit.
|
|
||||||
sigEd := sig.(SignatureEd25519)
|
|
||||||
sigEd[7] ^= byte(0x01)
|
|
||||||
sig = sigEd
|
|
||||||
|
|
||||||
assert.False(t, pubKey.VerifyBytes(msg, sig))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSignAndValidateSecp256k1(t *testing.T) {
|
|
||||||
privKey := GenPrivKeySecp256k1()
|
|
||||||
pubKey := privKey.PubKey()
|
|
||||||
|
|
||||||
msg := CRandBytes(128)
|
|
||||||
sig, err := privKey.Sign(msg)
|
|
||||||
require.Nil(t, err)
|
|
||||||
|
|
||||||
assert.True(t, pubKey.VerifyBytes(msg, sig))
|
|
||||||
|
|
||||||
// Mutate the signature, just one bit.
|
|
||||||
sigEd := sig.(SignatureSecp256k1)
|
|
||||||
sigEd[3] ^= byte(0x01)
|
|
||||||
sig = sigEd
|
|
||||||
|
|
||||||
assert.False(t, pubKey.VerifyBytes(msg, sig))
|
|
||||||
}
|
|
51
symmetric.go
51
symmetric.go
|
@ -1,51 +0,0 @@
|
||||||
package crypto
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
|
|
||||||
. "github.com/tendermint/tmlibs/common"
|
|
||||||
"golang.org/x/crypto/nacl/secretbox"
|
|
||||||
)
|
|
||||||
|
|
||||||
const nonceLen = 24
|
|
||||||
const secretLen = 32
|
|
||||||
|
|
||||||
// secret must be 32 bytes long. Use something like Sha256(Bcrypt(passphrase))
|
|
||||||
// The ciphertext is (secretbox.Overhead + 24) bytes longer than the plaintext.
|
|
||||||
// NOTE: call crypto.MixEntropy() first.
|
|
||||||
func EncryptSymmetric(plaintext []byte, secret []byte) (ciphertext []byte) {
|
|
||||||
if len(secret) != secretLen {
|
|
||||||
PanicSanity(Fmt("Secret must be 32 bytes long, got len %v", len(secret)))
|
|
||||||
}
|
|
||||||
nonce := CRandBytes(nonceLen)
|
|
||||||
nonceArr := [nonceLen]byte{}
|
|
||||||
copy(nonceArr[:], nonce)
|
|
||||||
secretArr := [secretLen]byte{}
|
|
||||||
copy(secretArr[:], secret)
|
|
||||||
ciphertext = make([]byte, nonceLen+secretbox.Overhead+len(plaintext))
|
|
||||||
copy(ciphertext, nonce)
|
|
||||||
secretbox.Seal(ciphertext[nonceLen:nonceLen], plaintext, &nonceArr, &secretArr)
|
|
||||||
return ciphertext
|
|
||||||
}
|
|
||||||
|
|
||||||
// secret must be 32 bytes long. Use something like Sha256(Bcrypt(passphrase))
|
|
||||||
// The ciphertext is (secretbox.Overhead + 24) bytes longer than the plaintext.
|
|
||||||
func DecryptSymmetric(ciphertext []byte, secret []byte) (plaintext []byte, err error) {
|
|
||||||
if len(secret) != secretLen {
|
|
||||||
PanicSanity(Fmt("Secret must be 32 bytes long, got len %v", len(secret)))
|
|
||||||
}
|
|
||||||
if len(ciphertext) <= secretbox.Overhead+nonceLen {
|
|
||||||
return nil, errors.New("Ciphertext is too short")
|
|
||||||
}
|
|
||||||
nonce := ciphertext[:nonceLen]
|
|
||||||
nonceArr := [nonceLen]byte{}
|
|
||||||
copy(nonceArr[:], nonce)
|
|
||||||
secretArr := [secretLen]byte{}
|
|
||||||
copy(secretArr[:], secret)
|
|
||||||
plaintext = make([]byte, len(ciphertext)-nonceLen-secretbox.Overhead)
|
|
||||||
_, ok := secretbox.Open(plaintext[:0], ciphertext[nonceLen:], &nonceArr, &secretArr)
|
|
||||||
if !ok {
|
|
||||||
return nil, errors.New("Ciphertext decryption failed")
|
|
||||||
}
|
|
||||||
return plaintext, nil
|
|
||||||
}
|
|
|
@ -1,42 +0,0 @@
|
||||||
package crypto
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
|
|
||||||
"golang.org/x/crypto/bcrypt"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestSimple(t *testing.T) {
|
|
||||||
|
|
||||||
MixEntropy([]byte("someentropy"))
|
|
||||||
|
|
||||||
plaintext := []byte("sometext")
|
|
||||||
secret := []byte("somesecretoflengththirtytwo===32")
|
|
||||||
ciphertext := EncryptSymmetric(plaintext, secret)
|
|
||||||
plaintext2, err := DecryptSymmetric(ciphertext, secret)
|
|
||||||
|
|
||||||
require.Nil(t, err, "%+v", err)
|
|
||||||
assert.Equal(t, plaintext, plaintext2)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSimpleWithKDF(t *testing.T) {
|
|
||||||
|
|
||||||
MixEntropy([]byte("someentropy"))
|
|
||||||
|
|
||||||
plaintext := []byte("sometext")
|
|
||||||
secretPass := []byte("somesecret")
|
|
||||||
secret, err := bcrypt.GenerateFromPassword(secretPass, 12)
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
secret = Sha256(secret)
|
|
||||||
|
|
||||||
ciphertext := EncryptSymmetric(plaintext, secret)
|
|
||||||
plaintext2, err := DecryptSymmetric(ciphertext, secret)
|
|
||||||
|
|
||||||
require.Nil(t, err, "%+v", err)
|
|
||||||
assert.Equal(t, plaintext, plaintext2)
|
|
||||||
}
|
|
|
@ -1,48 +0,0 @@
|
||||||
package tmhash
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto/sha256"
|
|
||||||
"hash"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
Size = 20
|
|
||||||
BlockSize = sha256.BlockSize
|
|
||||||
)
|
|
||||||
|
|
||||||
type sha256trunc struct {
|
|
||||||
sha256 hash.Hash
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h sha256trunc) Write(p []byte) (n int, err error) {
|
|
||||||
return h.sha256.Write(p)
|
|
||||||
}
|
|
||||||
func (h sha256trunc) Sum(b []byte) []byte {
|
|
||||||
shasum := h.sha256.Sum(b)
|
|
||||||
return shasum[:Size]
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h sha256trunc) Reset() {
|
|
||||||
h.sha256.Reset()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h sha256trunc) Size() int {
|
|
||||||
return Size
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h sha256trunc) BlockSize() int {
|
|
||||||
return h.sha256.BlockSize()
|
|
||||||
}
|
|
||||||
|
|
||||||
// New returns a new hash.Hash.
|
|
||||||
func New() hash.Hash {
|
|
||||||
return sha256trunc{
|
|
||||||
sha256: sha256.New(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sum returns the first 20 bytes of SHA256 of the bz.
|
|
||||||
func Sum(bz []byte) []byte {
|
|
||||||
hash := sha256.Sum256(bz)
|
|
||||||
return hash[:Size]
|
|
||||||
}
|
|
|
@ -1,23 +0,0 @@
|
||||||
package tmhash_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto/sha256"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"github.com/tendermint/go-crypto/tmhash"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestHash(t *testing.T) {
|
|
||||||
testVector := []byte("abc")
|
|
||||||
hasher := tmhash.New()
|
|
||||||
hasher.Write(testVector)
|
|
||||||
bz := hasher.Sum(nil)
|
|
||||||
|
|
||||||
hasher = sha256.New()
|
|
||||||
hasher.Write(testVector)
|
|
||||||
bz2 := hasher.Sum(nil)
|
|
||||||
bz2 = bz2[:20]
|
|
||||||
|
|
||||||
assert.Equal(t, bz, bz2)
|
|
||||||
}
|
|
|
@ -1,3 +0,0 @@
|
||||||
package crypto
|
|
||||||
|
|
||||||
const Version = "0.9.0-dev"
|
|
Loading…
Reference in New Issue