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" |