This reverts commit 96a3502126
.
# Conflicts:
# CHANGELOG.md
# Gopkg.lock
# Gopkg.toml
# LICENSE
# Makefile
# README.md
pull/1782/head
@ -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) | |||
} |
@ -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) | |||
} |
@ -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 |
@ -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 | |||
} |
@ -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) | |||
} |
@ -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) | |||
} | |||
} | |||
} | |||
*/ |
@ -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") | |||
} |
@ -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 | |||
} |
@ -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)) | |||
} |
@ -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" |