450 changed files with 840 additions and 65929 deletions
@ -0,0 +1,5 @@
@@ -0,0 +1,5 @@
|
||||
# Default ignored files |
||||
/shelf/ |
||||
/workspace.xml |
||||
# Editor-based HTTP Client requests |
||||
/httpRequests/ |
||||
@ -0,0 +1,8 @@
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<project version="4"> |
||||
<component name="ProjectModuleManager"> |
||||
<modules> |
||||
<module fileurl="file://$PROJECT_DIR$/.idea/next.orly.dev.iml" filepath="$PROJECT_DIR$/.idea/next.orly.dev.iml" /> |
||||
</modules> |
||||
</component> |
||||
</project> |
||||
@ -0,0 +1,6 @@
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<project version="4"> |
||||
<component name="VcsDirectoryMappings"> |
||||
<mapping directory="" vcs="Git" /> |
||||
</component> |
||||
</project> |
||||
@ -1,17 +0,0 @@
@@ -1,17 +0,0 @@
|
||||
ISC License |
||||
|
||||
Copyright (c) 2013-2017 The btcsuite developers |
||||
Copyright (c) 2015-2020 The Decred developers |
||||
Copyright (c) 2017 The Lightning Network Developers |
||||
|
||||
Permission to use, copy, modify, and distribute this software for any |
||||
purpose with or without fee is hereby granted, provided that the above |
||||
copyright notice and this permission notice appear in all copies. |
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
||||
@ -1,38 +0,0 @@
@@ -1,38 +0,0 @@
|
||||
# realy.lol/pkg/ec |
||||
|
||||
This is a full drop-in replacement for |
||||
[github.com/btcsuite/btcd/btcec](https://github.com/btcsuite/btcd/tree/master/btcec) |
||||
eliminating the import from the Decred repository, and including the chainhash |
||||
helper functions, needed for hashing messages for signatures. |
||||
|
||||
The decred specific tests also have been removed, as well as all tests that use |
||||
blake256 hashes as these are irrelevant to bitcoin and nostr. Some of them |
||||
remain present, commented out, in case it is worth regenerating the vectors |
||||
based on sha256 hashes, but on first blush it seems unlikely to be any benefit. |
||||
|
||||
This includes the old style compact secp256k1 ECDSA signatures, that recover the |
||||
public key rather than take a key as a parameter as used in Bitcoin |
||||
transactions, the new style Schnorr signatures, and the Musig2 implementation. |
||||
|
||||
BIP 340 Schnorr signatures are implemented including the variable length |
||||
message signing with the extra test vectors present and passing. |
||||
|
||||
The remainder of this document is from the original README.md. |
||||
|
||||
--- |
||||
|
||||
Package `ec` implements elliptic curve cryptography needed for working with |
||||
Bitcoin. It is designed so that it may be used with the standard |
||||
crypto/ecdsa packages provided with Go. |
||||
|
||||
A comprehensive suite of test is provided to ensure proper functionality. |
||||
|
||||
Package btcec was originally based on work from ThePiachu which is licensed |
||||
underthe same terms as Go, but it has signficantly diverged since then. The |
||||
btcsuite developers original is licensed under the liberal ISC license. |
||||
|
||||
## Installation and Updating |
||||
|
||||
```bash |
||||
$ go get mleku.dev/pkg/ec@latest |
||||
``` |
||||
@ -1,14 +0,0 @@
@@ -1,14 +0,0 @@
|
||||
Copyright © 2004-2011 []byte Internet Systems Consortium, Inc. ("ISC") |
||||
Copyright © 1995-2003 []byte Internet Software Consortium |
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any |
||||
purpose with or without fee is hereby granted, provided that the above |
||||
copyright notice and this permission notice appear in all copies. |
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH REGARD |
||||
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND |
||||
FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR |
||||
CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, |
||||
DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS |
||||
ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS |
||||
SOFTWARE. |
||||
@ -1,12 +0,0 @@
@@ -1,12 +0,0 @@
|
||||
= base58 |
||||
|
||||
image:http://img.shields.io/badge/license-ISC-blue.svg[ISC License,link=http://copyfree.org] |
||||
|
||||
Package base58 provides an API for encoding and decoding to and from the modified base58 encoding. |
||||
It also provides an API to do Base58Check encoding, as described https://en.bitcoin.it/wiki/Base58Check_encoding[here]. |
||||
|
||||
A comprehensive suite of tests is provided to ensure proper functionality. |
||||
|
||||
== License |
||||
|
||||
Package base58 is licensed under the http://copyfree.org[copyfree] ISC License. |
||||
@ -1,49 +0,0 @@
@@ -1,49 +0,0 @@
|
||||
// Copyright (c) 2015 The btcsuite developers
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// AUTOGENERATED by genalphabet.go; do not edit.
|
||||
|
||||
package base58 |
||||
|
||||
const ( |
||||
// Ciphers is the modified base58 Ciphers used by Bitcoin.
|
||||
Ciphers = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz" |
||||
|
||||
alphabetIdx0 = '1' |
||||
) |
||||
|
||||
var b58 = [256]byte{ |
||||
255, 255, 255, 255, 255, 255, 255, 255, |
||||
255, 255, 255, 255, 255, 255, 255, 255, |
||||
255, 255, 255, 255, 255, 255, 255, 255, |
||||
255, 255, 255, 255, 255, 255, 255, 255, |
||||
255, 255, 255, 255, 255, 255, 255, 255, |
||||
255, 255, 255, 255, 255, 255, 255, 255, |
||||
255, 0, 1, 2, 3, 4, 5, 6, |
||||
7, 8, 255, 255, 255, 255, 255, 255, |
||||
255, 9, 10, 11, 12, 13, 14, 15, |
||||
16, 255, 17, 18, 19, 20, 21, 255, |
||||
22, 23, 24, 25, 26, 27, 28, 29, |
||||
30, 31, 32, 255, 255, 255, 255, 255, |
||||
255, 33, 34, 35, 36, 37, 38, 39, |
||||
40, 41, 42, 43, 255, 44, 45, 46, |
||||
47, 48, 49, 50, 51, 52, 53, 54, |
||||
55, 56, 57, 255, 255, 255, 255, 255, |
||||
255, 255, 255, 255, 255, 255, 255, 255, |
||||
255, 255, 255, 255, 255, 255, 255, 255, |
||||
255, 255, 255, 255, 255, 255, 255, 255, |
||||
255, 255, 255, 255, 255, 255, 255, 255, |
||||
255, 255, 255, 255, 255, 255, 255, 255, |
||||
255, 255, 255, 255, 255, 255, 255, 255, |
||||
255, 255, 255, 255, 255, 255, 255, 255, |
||||
255, 255, 255, 255, 255, 255, 255, 255, |
||||
255, 255, 255, 255, 255, 255, 255, 255, |
||||
255, 255, 255, 255, 255, 255, 255, 255, |
||||
255, 255, 255, 255, 255, 255, 255, 255, |
||||
255, 255, 255, 255, 255, 255, 255, 255, |
||||
255, 255, 255, 255, 255, 255, 255, 255, |
||||
255, 255, 255, 255, 255, 255, 255, 255, |
||||
255, 255, 255, 255, 255, 255, 255, 255, |
||||
255, 255, 255, 255, 255, 255, 255, 255, |
||||
} |
||||
@ -1,142 +0,0 @@
@@ -1,142 +0,0 @@
|
||||
// Copyright (c) 2013-2015 The btcsuite developers
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package base58 |
||||
|
||||
import ( |
||||
"math/big" |
||||
) |
||||
|
||||
//go:generate go run genalphabet.go
|
||||
|
||||
var bigRadix = [...]*big.Int{ |
||||
big.NewInt(0), |
||||
big.NewInt(58), |
||||
big.NewInt(58 * 58), |
||||
big.NewInt(58 * 58 * 58), |
||||
big.NewInt(58 * 58 * 58 * 58), |
||||
big.NewInt(58 * 58 * 58 * 58 * 58), |
||||
big.NewInt(58 * 58 * 58 * 58 * 58 * 58), |
||||
big.NewInt(58 * 58 * 58 * 58 * 58 * 58 * 58), |
||||
big.NewInt(58 * 58 * 58 * 58 * 58 * 58 * 58 * 58), |
||||
big.NewInt(58 * 58 * 58 * 58 * 58 * 58 * 58 * 58 * 58), |
||||
bigRadix10, |
||||
} |
||||
|
||||
var bigRadix10 = big.NewInt(58 * 58 * 58 * 58 * 58 * 58 * 58 * 58 * 58 * 58) // 58^10
|
||||
|
||||
// Decode decodes a modified base58 string to a byte slice.
|
||||
func Decode(b string) []byte { |
||||
answer := big.NewInt(0) |
||||
scratch := new(big.Int) |
||||
|
||||
// Calculating with big.Int is slow for each iteration.
|
||||
// x += b58[b[i]] * j
|
||||
// j *= 58
|
||||
//
|
||||
// Instead we can try to do as much calculations on int64.
|
||||
// We can represent a 10 digit base58 number using an int64.
|
||||
//
|
||||
// Hence we'll try to convert 10, base58 digits at a time.
|
||||
// The rough idea is to calculate `t`, such that:
|
||||
//
|
||||
// t := b58[b[i+9]] * 58^9 ... + b58[b[i+1]] * 58^1 + b58[b[i]] * 58^0
|
||||
// x *= 58^10
|
||||
// x += t
|
||||
//
|
||||
// Of course, in addition, we'll need to handle boundary condition when `b` is not multiple of 58^10.
|
||||
// In that case we'll use the bigRadix[n] lookup for the appropriate power.
|
||||
for t := b; len(t) > 0; { |
||||
n := len(t) |
||||
if n > 10 { |
||||
n = 10 |
||||
} |
||||
|
||||
total := uint64(0) |
||||
for _, v := range t[:n] { |
||||
if v > 255 { |
||||
return []byte("") |
||||
} |
||||
|
||||
tmp := b58[v] |
||||
if tmp == 255 { |
||||
return []byte("") |
||||
} |
||||
total = total*58 + uint64(tmp) |
||||
} |
||||
|
||||
answer.Mul(answer, bigRadix[n]) |
||||
scratch.SetUint64(total) |
||||
answer.Add(answer, scratch) |
||||
|
||||
t = t[n:] |
||||
} |
||||
|
||||
tmpval := answer.Bytes() |
||||
|
||||
var numZeros int |
||||
for numZeros = 0; numZeros < len(b); numZeros++ { |
||||
if b[numZeros] != alphabetIdx0 { |
||||
break |
||||
} |
||||
} |
||||
flen := numZeros + len(tmpval) |
||||
val := make([]byte, flen) |
||||
copy(val[numZeros:], tmpval) |
||||
|
||||
return val |
||||
} |
||||
|
||||
// Encode encodes a byte slice to a modified base58 string.
|
||||
func Encode(b []byte) string { |
||||
x := new(big.Int) |
||||
x.SetBytes(b) |
||||
|
||||
// maximum length of output is log58(2^(8*len(b))) == len(b) * 8 / log(58)
|
||||
maxlen := int(float64(len(b))*1.365658237309761) + 1 |
||||
answer := make([]byte, 0, maxlen) |
||||
mod := new(big.Int) |
||||
for x.Sign() > 0 { |
||||
// Calculating with big.Int is slow for each iteration.
|
||||
// x, mod = x / 58, x % 58
|
||||
//
|
||||
// Instead we can try to do as much calculations on int64.
|
||||
// x, mod = x / 58^10, x % 58^10
|
||||
//
|
||||
// Which will give us mod, which is 10 digit base58 number.
|
||||
// We'll loop that 10 times to convert to the answer.
|
||||
|
||||
x.DivMod(x, bigRadix10, mod) |
||||
if x.Sign() == 0 { |
||||
// When x = 0, we need to ensure we don't add any extra zeros.
|
||||
m := mod.Int64() |
||||
for m > 0 { |
||||
answer = append(answer, Ciphers[m%58]) |
||||
m /= 58 |
||||
} |
||||
} else { |
||||
m := mod.Int64() |
||||
for i := 0; i < 10; i++ { |
||||
answer = append(answer, Ciphers[m%58]) |
||||
m /= 58 |
||||
} |
||||
} |
||||
} |
||||
|
||||
// leading zero bytes
|
||||
for _, i := range b { |
||||
if i != 0 { |
||||
break |
||||
} |
||||
answer = append(answer, alphabetIdx0) |
||||
} |
||||
|
||||
// reverse
|
||||
alen := len(answer) |
||||
for i := 0; i < alen/2; i++ { |
||||
answer[i], answer[alen-1-i] = answer[alen-1-i], answer[i] |
||||
} |
||||
|
||||
return string(answer) |
||||
} |
||||
@ -1,124 +0,0 @@
@@ -1,124 +0,0 @@
|
||||
// Copyright (c) 2013-2017 The btcsuite developers
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package base58_test |
||||
|
||||
import ( |
||||
"encoding/hex" |
||||
"testing" |
||||
|
||||
"next.orly.dev/pkg/crypto/ec/base58" |
||||
"next.orly.dev/pkg/utils" |
||||
) |
||||
|
||||
var stringTests = []struct { |
||||
in string |
||||
out string |
||||
}{ |
||||
{"", ""}, |
||||
{" ", "Z"}, |
||||
{"-", "n"}, |
||||
{"0", "q"}, |
||||
{"1", "r"}, |
||||
{"-1", "4SU"}, |
||||
{"11", "4k8"}, |
||||
{"abc", "ZiCa"}, |
||||
{"1234598760", "3mJr7AoUXx2Wqd"}, |
||||
{"abcdefghijklmnopqrstuvwxyz", "3yxU3u1igY8WkgtjK92fbJQCd4BZiiT1v25f"}, |
||||
{ |
||||
"00000000000000000000000000000000000000000000000000000000000000", |
||||
"3sN2THZeE9Eh9eYrwkvZqNstbHGvrxSAM7gXUXvyFQP8XvQLUqNCS27icwUeDT7ckHm4FUHM2mTVh1vbLmk7y", |
||||
}, |
||||
} |
||||
|
||||
var invalidStringTests = []struct { |
||||
in string |
||||
out string |
||||
}{ |
||||
{"0", ""}, |
||||
{"O", ""}, |
||||
{"I", ""}, |
||||
{"l", ""}, |
||||
{"3mJr0", ""}, |
||||
{"O3yxU", ""}, |
||||
{"3sNI", ""}, |
||||
{"4kl8", ""}, |
||||
{"0OIl", ""}, |
||||
{"!@#$%^&*()-_=+~`", ""}, |
||||
{"abcd\xd80", ""}, |
||||
{"abcd\U000020BF", ""}, |
||||
} |
||||
|
||||
var hexTests = []struct { |
||||
in string |
||||
out string |
||||
}{ |
||||
{"", ""}, |
||||
{"61", "2g"}, |
||||
{"626262", "a3gV"}, |
||||
{"636363", "aPEr"}, |
||||
{ |
||||
"73696d706c792061206c6f6e6720737472696e67", |
||||
"2cFupjhnEsSn59qHXstmK2ffpLv2", |
||||
}, |
||||
{ |
||||
"00eb15231dfceb60925886b67d065299925915aeb172c06647", |
||||
"1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L", |
||||
}, |
||||
{"516b6fcd0f", "ABnLTmg"}, |
||||
{"bf4f89001e670274dd", "3SEo3LWLoPntC"}, |
||||
{"572e4794", "3EFU7m"}, |
||||
{"ecac89cad93923c02321", "EJDM8drfXA6uyA"}, |
||||
{"10c8511e", "Rt5zm"}, |
||||
{"00000000000000000000", "1111111111"}, |
||||
{ |
||||
"000111d38e5fc9071ffcd20b4a763cc9ae4f252bb4e48fd66a835e252ada93ff480d6dd43dc62a641155a5", |
||||
"123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz", |
||||
}, |
||||
{ |
||||
"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", |
||||
"1cWB5HCBdLjAuqGGReWE3R3CguuwSjw6RHn39s2yuDRTS5NsBgNiFpWgAnEx6VQi8csexkgYw3mdYrMHr8x9i7aEwP8kZ7vccXWqKDvGv3u1GxFKPuAkn8JCPPGDMf3vMMnbzm6Nh9zh1gcNsMvH3ZNLmP5fSG6DGbbi2tuwMWPthr4boWwCxf7ewSgNQeacyozhKDDQQ1qL5fQFUW52QKUZDZ5fw3KXNQJMcNTcaB723LchjeKun7MuGW5qyCBZYzA1KjofN1gYBV3NqyhQJ3Ns746GNuf9N2pQPmHz4xpnSrrfCvy6TVVz5d4PdrjeshsWQwpZsZGzvbdAdN8MKV5QsBDY", |
||||
}, |
||||
} |
||||
|
||||
func TestBase58(t *testing.T) { |
||||
// Encode tests
|
||||
for x, test := range stringTests { |
||||
tmp := []byte(test.in) |
||||
if res := base58.Encode(tmp); res != test.out { |
||||
t.Errorf( |
||||
"Encode test #%d failed: got: %s want: %s", |
||||
x, res, test.out, |
||||
) |
||||
continue |
||||
} |
||||
} |
||||
|
||||
// Decode tests
|
||||
for x, test := range hexTests { |
||||
b, err := hex.DecodeString(test.in) |
||||
if err != nil { |
||||
t.Errorf("hex.DecodeString failed failed #%d: got: %s", x, test.in) |
||||
continue |
||||
} |
||||
if res := base58.Decode(test.out); !utils.FastEqual(res, b) { |
||||
t.Errorf( |
||||
"Decode test #%d failed: got: %q want: %q", |
||||
x, res, test.in, |
||||
) |
||||
continue |
||||
} |
||||
} |
||||
|
||||
// Decode with invalid input
|
||||
for x, test := range invalidStringTests { |
||||
if res := base58.Decode(test.in); string(res) != test.out { |
||||
t.Errorf( |
||||
"Decode invalidString test #%d failed: got: %q want: %q", |
||||
x, res, test.out, |
||||
) |
||||
continue |
||||
} |
||||
} |
||||
} |
||||
@ -1,47 +0,0 @@
@@ -1,47 +0,0 @@
|
||||
// Copyright (c) 2013-2014 The btcsuite developers
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package base58_test |
||||
|
||||
import ( |
||||
"bytes" |
||||
"testing" |
||||
|
||||
"next.orly.dev/pkg/crypto/ec/base58" |
||||
) |
||||
|
||||
var ( |
||||
raw5k = bytes.Repeat([]byte{0xff}, 5000) |
||||
raw100k = bytes.Repeat([]byte{0xff}, 100*1000) |
||||
encoded5k = base58.Encode(raw5k) |
||||
encoded100k = base58.Encode(raw100k) |
||||
) |
||||
|
||||
func BenchmarkBase58Encode_5K(b *testing.B) { |
||||
b.SetBytes(int64(len(raw5k))) |
||||
for i := 0; i < b.N; i++ { |
||||
base58.Encode(raw5k) |
||||
} |
||||
} |
||||
|
||||
func BenchmarkBase58Encode_100K(b *testing.B) { |
||||
b.SetBytes(int64(len(raw100k))) |
||||
for i := 0; i < b.N; i++ { |
||||
base58.Encode(raw100k) |
||||
} |
||||
} |
||||
|
||||
func BenchmarkBase58Decode_5K(b *testing.B) { |
||||
b.SetBytes(int64(len(encoded5k))) |
||||
for i := 0; i < b.N; i++ { |
||||
base58.Decode(encoded5k) |
||||
} |
||||
} |
||||
|
||||
func BenchmarkBase58Decode_100K(b *testing.B) { |
||||
b.SetBytes(int64(len(encoded100k))) |
||||
for i := 0; i < b.N; i++ { |
||||
base58.Decode(encoded100k) |
||||
} |
||||
} |
||||
@ -1,53 +0,0 @@
@@ -1,53 +0,0 @@
|
||||
// Copyright (c) 2013-2014 The btcsuite developers
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package base58 |
||||
|
||||
import ( |
||||
"errors" |
||||
|
||||
"github.com/minio/sha256-simd" |
||||
) |
||||
|
||||
// ErrChecksum indicates that the checksum of a check-encoded string does not verify against
|
||||
// the checksum.
|
||||
var ErrChecksum = errors.New("checksum error") |
||||
|
||||
// ErrInvalidFormat indicates that the check-encoded string has an invalid format.
|
||||
var ErrInvalidFormat = errors.New("invalid format: version and/or checksum bytes missing") |
||||
|
||||
// checksum: first four bytes of sha256^2
|
||||
func checksum(input []byte) (cksum [4]byte) { |
||||
h := sha256.Sum256(input) |
||||
h2 := sha256.Sum256(h[:]) |
||||
copy(cksum[:], h2[:4]) |
||||
return |
||||
} |
||||
|
||||
// CheckEncode prepends a version byte and appends a four byte checksum.
|
||||
func CheckEncode(input []byte, version byte) string { |
||||
b := make([]byte, 0, 1+len(input)+4) |
||||
b = append(b, version) |
||||
b = append(b, input...) |
||||
cksum := checksum(b) |
||||
b = append(b, cksum[:]...) |
||||
return Encode(b) |
||||
} |
||||
|
||||
// CheckDecode decodes a string that was encoded with CheckEncode and verifies the checksum.
|
||||
func CheckDecode(input string) (result []byte, version byte, err error) { |
||||
decoded := Decode(input) |
||||
if len(decoded) < 5 { |
||||
return nil, 0, ErrInvalidFormat |
||||
} |
||||
version = decoded[0] |
||||
var cksum [4]byte |
||||
copy(cksum[:], decoded[len(decoded)-4:]) |
||||
if checksum(decoded[:len(decoded)-4]) != cksum { |
||||
return nil, 0, ErrChecksum |
||||
} |
||||
payload := decoded[1 : len(decoded)-4] |
||||
result = append(result, payload...) |
||||
return |
||||
} |
||||
@ -1,87 +0,0 @@
@@ -1,87 +0,0 @@
|
||||
// Copyright (c) 2013-2014 The btcsuite developers
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package base58_test |
||||
|
||||
import ( |
||||
"testing" |
||||
|
||||
"next.orly.dev/pkg/crypto/ec/base58" |
||||
) |
||||
|
||||
var checkEncodingStringTests = []struct { |
||||
version byte |
||||
in string |
||||
out string |
||||
}{ |
||||
{20, "", "3MNQE1X"}, |
||||
{20, " ", "B2Kr6dBE"}, |
||||
{20, "-", "B3jv1Aft"}, |
||||
{20, "0", "B482yuaX"}, |
||||
{20, "1", "B4CmeGAC"}, |
||||
{20, "-1", "mM7eUf6kB"}, |
||||
{20, "11", "mP7BMTDVH"}, |
||||
{20, "abc", "4QiVtDjUdeq"}, |
||||
{20, "1234598760", "ZmNb8uQn5zvnUohNCEPP"}, |
||||
{ |
||||
20, "abcdefghijklmnopqrstuvwxyz", |
||||
"K2RYDcKfupxwXdWhSAxQPCeiULntKm63UXyx5MvEH2", |
||||
}, |
||||
{ |
||||
20, "00000000000000000000000000000000000000000000000000000000000000", |
||||
"bi1EWXwJay2udZVxLJozuTb8Meg4W9c6xnmJaRDjg6pri5MBAxb9XwrpQXbtnqEoRV5U2pixnFfwyXC8tRAVC8XxnjK", |
||||
}, |
||||
} |
||||
|
||||
func TestBase58Check(t *testing.T) { |
||||
for x, test := range checkEncodingStringTests { |
||||
// test encoding
|
||||
if res := base58.CheckEncode( |
||||
[]byte(test.in), |
||||
test.version, |
||||
); res != test.out { |
||||
t.Errorf( |
||||
"CheckEncode test #%d failed: got %s, want: %s", x, res, |
||||
test.out, |
||||
) |
||||
} |
||||
|
||||
// test decoding
|
||||
res, version, err := base58.CheckDecode(test.out) |
||||
switch { |
||||
case err != nil: |
||||
t.Errorf("CheckDecode test #%d failed with err: %v", x, err) |
||||
|
||||
case version != test.version: |
||||
t.Errorf( |
||||
"CheckDecode test #%d failed: got version: %d want: %d", x, |
||||
version, test.version, |
||||
) |
||||
|
||||
case string(res) != test.in: |
||||
t.Errorf( |
||||
"CheckDecode test #%d failed: got: %s want: %s", x, res, |
||||
test.in, |
||||
) |
||||
} |
||||
} |
||||
|
||||
// test the two decoding failure cases
|
||||
// case 1: checksum error
|
||||
_, _, err := base58.CheckDecode("3MNQE1Y") |
||||
if err != base58.ErrChecksum { |
||||
t.Error("Checkdecode test failed, expected ErrChecksum") |
||||
} |
||||
// case 2: invalid formats (string lengths below 5 mean the version byte and/or the checksum
|
||||
// bytes are missing).
|
||||
testString := "" |
||||
for len := 0; len < 4; len++ { |
||||
testString += "x" |
||||
_, _, err = base58.CheckDecode(testString) |
||||
if err != base58.ErrInvalidFormat { |
||||
t.Error("Checkdecode test failed, expected ErrInvalidFormat") |
||||
} |
||||
} |
||||
|
||||
} |
||||
@ -1,17 +0,0 @@
@@ -1,17 +0,0 @@
|
||||
#!/bin/sh |
||||
|
||||
# This script uses gocov to generate a test coverage report. |
||||
# The gocov tool my be obtained with the following command: |
||||
# go get github.com/axw/gocov/gocov |
||||
# |
||||
# It will be installed to $GOPATH/bin, so ensure that location is in your $PATH. |
||||
|
||||
# Check for gocov. |
||||
type gocov >/dev/null 2>&1 |
||||
if [ $? -ne 0 ]; then |
||||
echo >&2 "This script requires the gocov tool." |
||||
echo >&2 "You may obtain it with the following command:" |
||||
echo >&2 "go get github.com/axw/gocov/gocov" |
||||
exit 1 |
||||
fi |
||||
gocov test | gocov report |
||||
@ -1,29 +0,0 @@
@@ -1,29 +0,0 @@
|
||||
// Copyright (c) 2014 The btcsuite developers
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
/* |
||||
Package base58 provides an API for working with modified base58 and Base58Check |
||||
encodings. |
||||
|
||||
# Modified Base58 Encoding |
||||
|
||||
Standard base58 encoding is similar to standard base64 encoding except, as the |
||||
name implies, it uses a 58 character Ciphers which results in an alphanumeric |
||||
string and allows some characters which are problematic for humans to be |
||||
excluded. Due to this, there can be various base58 alphabets. |
||||
|
||||
The modified base58 Ciphers used by Bitcoin, and hence this package, omits the |
||||
0, O, I, and l characters that look the same in many fonts and are therefore |
||||
hard to humans to distinguish. |
||||
|
||||
# Base58Check Encoding Scheme |
||||
|
||||
The Base58Check encoding scheme is primarily used for Bitcoin addresses at the |
||||
time of this writing, however it can be used to generically encode arbitrary |
||||
byte arrays into human-readable strings along with a version byte that can be |
||||
used to differentiate the same payload. For Bitcoin addresses, the extra |
||||
version is used to differentiate the network of otherwise identical public keys |
||||
which helps prevent using an address intended for one network on another. |
||||
*/ |
||||
package base58 |
||||
@ -1,71 +0,0 @@
@@ -1,71 +0,0 @@
|
||||
// Copyright (c) 2014 The btcsuite developers
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package base58_test |
||||
|
||||
import ( |
||||
"fmt" |
||||
|
||||
"next.orly.dev/pkg/crypto/ec/base58" |
||||
) |
||||
|
||||
// This example demonstrates how to decode modified base58 encoded data.
|
||||
func ExampleDecode() { |
||||
// Decode example modified base58 encoded data.
|
||||
encoded := "25JnwSn7XKfNQ" |
||||
decoded := base58.Decode(encoded) |
||||
|
||||
// Show the decoded data.
|
||||
fmt.Println("Decoded Data:", string(decoded)) |
||||
|
||||
// Output:
|
||||
// Decoded Data: Test data
|
||||
} |
||||
|
||||
// This example demonstrates how to encode data using the modified base58
|
||||
// encoding scheme.
|
||||
func ExampleEncode() { |
||||
// Encode example data with the modified base58 encoding scheme.
|
||||
data := []byte("Test data") |
||||
encoded := base58.Encode(data) |
||||
|
||||
// Show the encoded data.
|
||||
fmt.Println("Encoded Data:", encoded) |
||||
|
||||
// Output:
|
||||
// Encoded Data: 25JnwSn7XKfNQ
|
||||
} |
||||
|
||||
// This example demonstrates how to decode Base58Check encoded data.
|
||||
func ExampleCheckDecode() { |
||||
// Decode an example Base58Check encoded data.
|
||||
encoded := "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa" |
||||
decoded, version, err := base58.CheckDecode(encoded) |
||||
if err != nil { |
||||
fmt.Println(err) |
||||
return |
||||
} |
||||
|
||||
// Show the decoded data.
|
||||
fmt.Printf("Decoded data: %x\n", decoded) |
||||
fmt.Println("Version Byte:", version) |
||||
|
||||
// Output:
|
||||
// Decoded data: 62e907b15cbf27d5425399ebf6f0fb50ebb88f18
|
||||
// Version Byte: 0
|
||||
} |
||||
|
||||
// This example demonstrates how to encode data using the Base58Check encoding
|
||||
// scheme.
|
||||
func ExampleCheckEncode() { |
||||
// Encode example data with the Base58Check encoding scheme.
|
||||
data := []byte("Test data") |
||||
encoded := base58.CheckEncode(data, 0) |
||||
|
||||
// Show the encoded data.
|
||||
fmt.Println("Encoded Data:", encoded) |
||||
|
||||
// Output:
|
||||
// Encoded Data: 182iP79GRURMp7oMHDU
|
||||
} |
||||
@ -1,77 +0,0 @@
@@ -1,77 +0,0 @@
|
||||
// Copyright (c) 2015 The btcsuite developers
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main |
||||
|
||||
import ( |
||||
"bytes" |
||||
"io" |
||||
"log" |
||||
"os" |
||||
"strconv" |
||||
) |
||||
|
||||
var ( |
||||
start = []byte(`// Copyright (c) 2015 The btcsuite developers
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// AUTOGENERATED by genalphabet.go; do not edit.
|
||||
|
||||
package base58 |
||||
|
||||
const ( |
||||
// Ciphers is the modified base58 alphabet used by Bitcoin.
|
||||
Ciphers = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz" |
||||
|
||||
alphabetIdx0 = '1' |
||||
) |
||||
|
||||
var b58 = [256]byte{`) |
||||
|
||||
end = []byte(`}`) |
||||
|
||||
alphabet = []byte("123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz") |
||||
tab = []byte("\t") |
||||
invalid = []byte("255") |
||||
comma = []byte(",") |
||||
space = []byte(" ") |
||||
nl = []byte("\n") |
||||
) |
||||
|
||||
func write(w io.Writer, b []byte) { |
||||
_, err := w.Write(b) |
||||
if err != nil { |
||||
log.Fatal(err) |
||||
} |
||||
} |
||||
|
||||
func main() { |
||||
fi, err := os.Create("alphabet.go") |
||||
if err != nil { |
||||
log.Fatal(err) |
||||
} |
||||
defer fi.Close() |
||||
|
||||
write(fi, start) |
||||
write(fi, nl) |
||||
for i := byte(0); i < 32; i++ { |
||||
write(fi, tab) |
||||
for j := byte(0); j < 8; j++ { |
||||
idx := bytes.IndexByte(alphabet, i*8+j) |
||||
if idx == -1 { |
||||
write(fi, invalid) |
||||
} else { |
||||
write(fi, strconv.AppendInt(nil, int64(idx), 10)) |
||||
} |
||||
write(fi, comma) |
||||
if j != 7 { |
||||
write(fi, space) |
||||
} |
||||
} |
||||
write(fi, nl) |
||||
} |
||||
write(fi, end) |
||||
write(fi, nl) |
||||
} |
||||
@ -1,27 +0,0 @@
@@ -1,27 +0,0 @@
|
||||
= bech32 |
||||
|
||||
image:http://img.shields.io/badge/license-ISC-blue.svg[ISC License,link=http://copyfree.org] |
||||
image:https://godoc.org/realy.lol/pkg/ec/bech32?status.png[GoDoc,link=http://godoc.org/realy.lol/pkg/ec/bech32] |
||||
|
||||
Package bech32 provides a Go implementation of the bech32 format specified in |
||||
https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki[BIP 173]. |
||||
|
||||
Test vectors from BIP 173 are added to ensure compatibility with the BIP. |
||||
|
||||
== Installation and Updating |
||||
|
||||
[source,bash] |
||||
---- |
||||
$ go get -u mleku.dev/pkg/ec/bech32 |
||||
---- |
||||
|
||||
== Examples |
||||
|
||||
* http://godoc.org/realy.lol/pkg/ec/bech32#example-Bech32Decode[Bech32 decode Example] |
||||
Demonstrates how to decode a bech32 encoded string. |
||||
* http://godoc.org/realy.lol/pkg/ec/bech32#example-BechEncode[Bech32 encode Example] |
||||
Demonstrates how to encode data into a bech32 string. |
||||
|
||||
== License |
||||
|
||||
Package bech32 is licensed under the http://copyfree.org[copyfree] ISC License. |
||||
@ -1,411 +0,0 @@
@@ -1,411 +0,0 @@
|
||||
// Copyright (c) 2017 The btcsuite developers
|
||||
// Copyright (c) 2019 The Decred developers
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package bech32 |
||||
|
||||
import ( |
||||
"bytes" |
||||
"strings" |
||||
) |
||||
|
||||
// Charset is the set of characters used in the data section of bech32 strings.
|
||||
// Note that this is ordered, such that for a given charset[i], i is the binary
|
||||
// value of the character.
|
||||
//
|
||||
// This wasn't exported in the original lol.
|
||||
const Charset = "qpzry9x8gf2tvdw0s3jn54khce6mua7l" |
||||
|
||||
// gen encodes the generator polynomial for the bech32 BCH checksum.
|
||||
var gen = []int{0x3b6a57b2, 0x26508e6d, 0x1ea119fa, 0x3d4233dd, 0x2a1462b3} |
||||
|
||||
// toBytes converts each character in the string 'chars' to the value of the
|
||||
// index of the corresponding character in 'charset'.
|
||||
func toBytes(chars []byte) ([]byte, error) { |
||||
decoded := make([]byte, 0, len(chars)) |
||||
for i := 0; i < len(chars); i++ { |
||||
index := strings.IndexByte(Charset, chars[i]) |
||||
if index < 0 { |
||||
return nil, ErrNonCharsetChar(chars[i]) |
||||
} |
||||
decoded = append(decoded, byte(index)) |
||||
} |
||||
return decoded, nil |
||||
} |
||||
|
||||
// bech32Polymod calculates the BCH checksum for a given hrp, values and
|
||||
// checksum data. Checksum is optional, and if nil a 0 checksum is assumed.
|
||||
//
|
||||
// Values and checksum (if provided) MUST be encoded as 5 bits per element (base
|
||||
// 32), otherwise the results are undefined.
|
||||
//
|
||||
// For more details on the polymod calculation, please refer to BIP 173.
|
||||
func bech32Polymod(hrp []byte, values, checksum []byte) int { |
||||
check := 1 |
||||
// Account for the high bits of the HRP in the checksum.
|
||||
for i := 0; i < len(hrp); i++ { |
||||
b := check >> 25 |
||||
hiBits := int(hrp[i]) >> 5 |
||||
check = (check&0x1ffffff)<<5 ^ hiBits |
||||
for i := 0; i < 5; i++ { |
||||
if (b>>uint(i))&1 == 1 { |
||||
check ^= gen[i] |
||||
} |
||||
} |
||||
} |
||||
// Account for the separator (0) between high and low bits of the HRP.
|
||||
// x^0 == x, so we eliminate the redundant xor used in the other rounds.
|
||||
b := check >> 25 |
||||
check = (check & 0x1ffffff) << 5 |
||||
for i := 0; i < 5; i++ { |
||||
if (b>>uint(i))&1 == 1 { |
||||
check ^= gen[i] |
||||
} |
||||
} |
||||
// Account for the low bits of the HRP.
|
||||
for i := 0; i < len(hrp); i++ { |
||||
b := check >> 25 |
||||
loBits := int(hrp[i]) & 31 |
||||
check = (check&0x1ffffff)<<5 ^ loBits |
||||
for i := 0; i < 5; i++ { |
||||
if (b>>uint(i))&1 == 1 { |
||||
check ^= gen[i] |
||||
} |
||||
} |
||||
} |
||||
// Account for the values.
|
||||
for _, v := range values { |
||||
b := check >> 25 |
||||
check = (check&0x1ffffff)<<5 ^ int(v) |
||||
for i := 0; i < 5; i++ { |
||||
if (b>>uint(i))&1 == 1 { |
||||
check ^= gen[i] |
||||
} |
||||
} |
||||
} |
||||
if checksum == nil { |
||||
// A nil checksum is used during encoding, so assume all bytes are zero.
|
||||
// x^0 == x, so we eliminate the redundant xor used in the other rounds.
|
||||
for v := 0; v < 6; v++ { |
||||
b := check >> 25 |
||||
check = (check & 0x1ffffff) << 5 |
||||
for i := 0; i < 5; i++ { |
||||
if (b>>uint(i))&1 == 1 { |
||||
check ^= gen[i] |
||||
} |
||||
} |
||||
} |
||||
} else { |
||||
// Checksum is provided during decoding, so use it.
|
||||
for _, v := range checksum { |
||||
b := check >> 25 |
||||
check = (check&0x1ffffff)<<5 ^ int(v) |
||||
for i := 0; i < 5; i++ { |
||||
if (b>>uint(i))&1 == 1 { |
||||
check ^= gen[i] |
||||
} |
||||
} |
||||
} |
||||
} |
||||
return check |
||||
} |
||||
|
||||
// writeBech32Checksum calculates the checksum data expected for a string that
|
||||
// will have the given hrp and payload data and writes it to the provided string
|
||||
// builder.
|
||||
//
|
||||
// The payload data MUST be encoded as a base 32 (5 bits per element) byte slice
|
||||
// and the hrp MUST only use the allowed character set (ascii chars between 33
|
||||
// and 126), otherwise the results are undefined.
|
||||
//
|
||||
// For more details on the checksum calculation, please refer to BIP 173.
|
||||
func writeBech32Checksum( |
||||
hrp []byte, data []byte, bldr *bytes.Buffer, |
||||
version Version, |
||||
) { |
||||
|
||||
bech32Const := int(VersionToConsts[version]) |
||||
polymod := bech32Polymod(hrp, data, nil) ^ bech32Const |
||||
for i := 0; i < 6; i++ { |
||||
b := byte((polymod >> uint(5*(5-i))) & 31) |
||||
// This can't fail, given we explicitly cap the previous b byte by the
|
||||
// first 31 bits.
|
||||
c := Charset[b] |
||||
bldr.WriteByte(c) |
||||
} |
||||
} |
||||
|
||||
// bech32VerifyChecksum verifies whether the bech32 string specified by the
|
||||
// provided hrp and payload data (encoded as 5 bits per element byte slice) has
|
||||
// the correct checksum suffix. The version of bech32 used (bech32 OG, or
|
||||
// bech32m) is also returned to allow the caller to perform proper address
|
||||
// validation (segwitv0 should use bech32, v1+ should use bech32m).
|
||||
//
|
||||
// Data MUST have more than 6 elements, otherwise this function panics.
|
||||
//
|
||||
// For more details on the checksum verification, please refer to BIP 173.
|
||||
func bech32VerifyChecksum(hrp []byte, data []byte) (Version, bool) { |
||||
checksum := data[len(data)-6:] |
||||
values := data[:len(data)-6] |
||||
polymod := bech32Polymod(hrp, values, checksum) |
||||
// Before BIP-350, we'd always check this against a static constant of
|
||||
// 1 to know if the checksum was computed properly. As we want to
|
||||
// generically support decoding for bech32m as well as bech32, we'll
|
||||
// look up the returned value and compare it to the set of defined
|
||||
// constants.
|
||||
bech32Version, ok := ConstsToVersion[ChecksumConst(polymod)] |
||||
if ok { |
||||
return bech32Version, true |
||||
} |
||||
return VersionUnknown, false |
||||
} |
||||
|
||||
// DecodeNoLimit is a bech32 checksum version aware arbitrary string length
|
||||
// decoder. This function will return the version of the decoded checksum
|
||||
// constant so higher level validation can be performed to ensure the correct
|
||||
// version of bech32 was used when encoding.
|
||||
func decodeNoLimit(bech []byte) ([]byte, []byte, Version, error) { |
||||
// The minimum allowed size of a bech32 string is 8 characters, since it
|
||||
// needs a non-empty HRP, a separator, and a 6 character checksum.
|
||||
if len(bech) < 8 { |
||||
return nil, nil, VersionUnknown, ErrInvalidLength(len(bech)) |
||||
} |
||||
// Only ASCII characters between 33 and 126 are allowed.
|
||||
var hasLower, hasUpper bool |
||||
for i := 0; i < len(bech); i++ { |
||||
if bech[i] < 33 || bech[i] > 126 { |
||||
return nil, nil, VersionUnknown, ErrInvalidCharacter(bech[i]) |
||||
} |
||||
// The characters must be either all lowercase or all uppercase. Testing
|
||||
// directly with ascii codes is safe here, given the previous test.
|
||||
hasLower = hasLower || (bech[i] >= 97 && bech[i] <= 122) |
||||
hasUpper = hasUpper || (bech[i] >= 65 && bech[i] <= 90) |
||||
if hasLower && hasUpper { |
||||
return nil, nil, VersionUnknown, ErrMixedCase{} |
||||
} |
||||
} |
||||
// Bech32 standard uses only the lowercase for of strings for checksum
|
||||
// calculation.
|
||||
if hasUpper { |
||||
bech = bytes.ToLower(bech) |
||||
} |
||||
// The string is invalid if the last '1' is non-existent, it is the
|
||||
// first character of the string (no human-readable part) or one of the
|
||||
// last 6 characters of the string (since checksum cannot contain '1').
|
||||
one := bytes.LastIndexByte(bech, '1') |
||||
if one < 1 || one+7 > len(bech) { |
||||
return nil, nil, VersionUnknown, ErrInvalidSeparatorIndex(one) |
||||
} |
||||
// The human-readable part is everything before the last '1'.
|
||||
hrp := bech[:one] |
||||
data := bech[one+1:] |
||||
// Each character corresponds to the byte with value of the index in
|
||||
// 'charset'.
|
||||
decoded, err := toBytes(data) |
||||
if err != nil { |
||||
return nil, nil, VersionUnknown, err |
||||
} |
||||
// Verify if the checksum (stored inside decoded[:]) is valid, given the
|
||||
// previously decoded hrp.
|
||||
bech32Version, ok := bech32VerifyChecksum(hrp, decoded) |
||||
if !ok { |
||||
// Invalid checksum. Calculate what it should have been, so that the
|
||||
// error contains this information.
|
||||
//
|
||||
// Extract the payload bytes and actual checksum in the string.
|
||||
actual := bech[len(bech)-6:] |
||||
payload := decoded[:len(decoded)-6] |
||||
// Calculate the expected checksum, given the hrp and payload
|
||||
// data. We'll actually compute _both_ possibly valid checksum
|
||||
// to further aide in debugging.
|
||||
var expectedBldr bytes.Buffer |
||||
expectedBldr.Grow(6) |
||||
writeBech32Checksum(hrp, payload, &expectedBldr, Version0) |
||||
expectedVersion0 := expectedBldr.String() |
||||
var b strings.Builder |
||||
b.Grow(6) |
||||
writeBech32Checksum(hrp, payload, &expectedBldr, VersionM) |
||||
expectedVersionM := expectedBldr.String() |
||||
err = ErrInvalidChecksum{ |
||||
Expected: expectedVersion0, |
||||
ExpectedM: expectedVersionM, |
||||
Actual: string(actual), |
||||
} |
||||
return nil, nil, VersionUnknown, err |
||||
} |
||||
// We exclude the last 6 bytes, which is the checksum.
|
||||
return hrp, decoded[:len(decoded)-6], bech32Version, nil |
||||
} |
||||
|
||||
// DecodeNoLimit decodes a bech32 encoded string, returning the human-readable
|
||||
// part and the data part excluding the checksum. This function does NOT
|
||||
// validate against the BIP-173 maximum length allowed for bech32 strings and
|
||||
// is meant for use in custom applications (such as lightning network payment
|
||||
// requests), NOT on-chain addresses.
|
||||
//
|
||||
// Note that the returned data is 5-bit (base32) encoded and the human-readable
|
||||
// part will be lowercase.
|
||||
func DecodeNoLimit(bech []byte) ([]byte, []byte, error) { |
||||
hrp, data, _, err := decodeNoLimit(bech) |
||||
return hrp, data, err |
||||
} |
||||
|
||||
// Decode decodes a bech32 encoded string, returning the human-readable part and
|
||||
// the data part excluding the checksum.
|
||||
//
|
||||
// Note that the returned data is 5-bit (base32) encoded and the human-readable
|
||||
// part will be lowercase.
|
||||
func Decode(bech []byte) ([]byte, []byte, error) { |
||||
// The maximum allowed length for a bech32 string is 90.
|
||||
if len(bech) > 90 { |
||||
return nil, nil, ErrInvalidLength(len(bech)) |
||||
} |
||||
hrp, data, _, err := decodeNoLimit(bech) |
||||
return hrp, data, err |
||||
} |
||||
|
||||
// DecodeGeneric is identical to the existing Decode method, but will also
|
||||
// return bech32 version that matches the decoded checksum. This method should
|
||||
// be used when decoding segwit addresses, as it enables additional
|
||||
// verification to ensure the proper checksum is used.
|
||||
func DecodeGeneric(bech []byte) ([]byte, []byte, Version, error) { |
||||
// The maximum allowed length for a bech32 string is 90.
|
||||
if len(bech) > 90 { |
||||
return nil, nil, VersionUnknown, ErrInvalidLength(len(bech)) |
||||
} |
||||
return decodeNoLimit(bech) |
||||
} |
||||
|
||||
// encodeGeneric is the base bech32 encoding function that is aware of the
|
||||
// existence of the checksum versions. This method is private, as the Encode
|
||||
// and EncodeM methods are intended to be used instead.
|
||||
func encodeGeneric(hrp []byte, data []byte, version Version) ([]byte, error) { |
||||
// The resulting bech32 string is the concatenation of the lowercase
|
||||
// hrp, the separator 1, data and the 6-byte checksum.
|
||||
hrp = bytes.ToLower(hrp) |
||||
var bldr bytes.Buffer |
||||
bldr.Grow(len(hrp) + 1 + len(data) + 6) |
||||
bldr.Write(hrp) |
||||
bldr.WriteString("1") |
||||
// Write the data part, using the bech32 charset.
|
||||
for _, b := range data { |
||||
if int(b) >= len(Charset) { |
||||
return nil, ErrInvalidDataByte(b) |
||||
} |
||||
bldr.WriteByte(Charset[b]) |
||||
} |
||||
// Calculate and write the checksum of the data.
|
||||
writeBech32Checksum(hrp, data, &bldr, version) |
||||
return bldr.Bytes(), nil |
||||
} |
||||
|
||||
// Encode encodes a byte slice into a bech32 string with the given
|
||||
// human-readable part (HRP). The HRP will be converted to lowercase if needed
|
||||
// since mixed cased encodings are not permitted and lowercase is used for
|
||||
// checksum purposes. Note that the bytes must each encode 5 bits (base32).
|
||||
func Encode(hrp, data []byte) ([]byte, error) { |
||||
return encodeGeneric(hrp, data, Version0) |
||||
} |
||||
|
||||
// EncodeM is the exactly same as the Encode method, but it uses the new
|
||||
// bech32m constant instead of the original one. It should be used whenever one
|
||||
// attempts to encode a segwit address of v1 and beyond.
|
||||
func EncodeM(hrp, data []byte) ([]byte, error) { |
||||
return encodeGeneric(hrp, data, VersionM) |
||||
} |
||||
|
||||
// ConvertBits converts a byte slice where each byte is encoding fromBits bits,
|
||||
// to a byte slice where each byte is encoding toBits bits.
|
||||
func ConvertBits(data []byte, fromBits, toBits uint8, pad bool) ( |
||||
[]byte, |
||||
error, |
||||
) { |
||||
|
||||
if fromBits < 1 || fromBits > 8 || toBits < 1 || toBits > 8 { |
||||
return nil, ErrInvalidBitGroups{} |
||||
} |
||||
// Determine the maximum size the resulting array can have after base
|
||||
// conversion, so that we can size it a single time. This might be off
|
||||
// by a byte depending on whether padding is used or not and if the input
|
||||
// data is a multiple of both fromBits and toBits, but we ignore that and
|
||||
// just size it to the maximum possible.
|
||||
maxSize := len(data)*int(fromBits)/int(toBits) + 1 |
||||
// The final bytes, each byte encoding toBits bits.
|
||||
regrouped := make([]byte, 0, maxSize) |
||||
// Keep track of the next byte we create and how many bits we have
|
||||
// added to it out of the toBits goal.
|
||||
nextByte := byte(0) |
||||
filledBits := uint8(0) |
||||
for _, b := range data { |
||||
// Discard unused bits.
|
||||
b <<= 8 - fromBits |
||||
// How many bits remaining to extract from the input data.
|
||||
remFromBits := fromBits |
||||
for remFromBits > 0 { |
||||
// How many bits remaining to be added to the next byte.
|
||||
remToBits := toBits - filledBits |
||||
// The number of bytes to next extract is the minimum of
|
||||
// remFromBits and remToBits.
|
||||
toExtract := remFromBits |
||||
if remToBits < toExtract { |
||||
toExtract = remToBits |
||||
} |
||||
// Add the next bits to nextByte, shifting the already
|
||||
// added bits to the left.
|
||||
nextByte = (nextByte << toExtract) | (b >> (8 - toExtract)) |
||||
// Discard the bits we just extracted and get ready for
|
||||
// next iteration.
|
||||
b <<= toExtract |
||||
remFromBits -= toExtract |
||||
filledBits += toExtract |
||||
// If the nextByte is completely filled, we add it to
|
||||
// our regrouped bytes and start on the next byte.
|
||||
if filledBits == toBits { |
||||
regrouped = append(regrouped, nextByte) |
||||
filledBits = 0 |
||||
nextByte = 0 |
||||
} |
||||
} |
||||
} |
||||
// We pad any unfinished group if specified.
|
||||
if pad && filledBits > 0 { |
||||
nextByte <<= toBits - filledBits |
||||
regrouped = append(regrouped, nextByte) |
||||
filledBits = 0 |
||||
nextByte = 0 |
||||
} |
||||
// Any incomplete group must be <= 4 bits, and all zeroes.
|
||||
if filledBits > 0 && (filledBits > 4 || nextByte != 0) { |
||||
return nil, ErrInvalidIncompleteGroup{} |
||||
} |
||||
return regrouped, nil |
||||
} |
||||
|
||||
// EncodeFromBase256 converts a base256-encoded byte slice into a base32-encoded
|
||||
// byte slice and then encodes it into a bech32 string with the given
|
||||
// human-readable part (HRP). The HRP will be converted to lowercase if needed
|
||||
// since mixed cased encodings are not permitted and lowercase is used for
|
||||
// checksum purposes.
|
||||
func EncodeFromBase256(hrp, data []byte) ([]byte, error) { |
||||
converted, err := ConvertBits(data, 8, 5, true) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return Encode(hrp, converted) |
||||
} |
||||
|
||||
// DecodeToBase256 decodes a bech32-encoded string into its associated
|
||||
// human-readable part (HRP) and base32-encoded data, converts that data to a
|
||||
// base256-encoded byte slice and returns it along with the lowercase HRP.
|
||||
func DecodeToBase256(bech []byte) ([]byte, []byte, error) { |
||||
hrp, data, err := Decode(bech) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
converted, err := ConvertBits(data, 5, 8, false) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
return hrp, converted, nil |
||||
} |
||||
@ -1,776 +0,0 @@
@@ -1,776 +0,0 @@
|
||||
// Copyright (c) 2017-2020 The btcsuite developers
|
||||
// Copyright (c) 2019 The Decred developers
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package bech32 |
||||
|
||||
import ( |
||||
"bytes" |
||||
"encoding/hex" |
||||
"errors" |
||||
"fmt" |
||||
"strings" |
||||
"testing" |
||||
|
||||
"next.orly.dev/pkg/utils" |
||||
) |
||||
|
||||
// TestBech32 tests whether decoding and re-encoding the valid BIP-173 test
|
||||
// vectors works and if decoding invalid test vectors fails for the correct
|
||||
// reason.
|
||||
func TestBech32(t *testing.T) { |
||||
tests := []struct { |
||||
str string |
||||
expectedError error |
||||
}{ |
||||
{"A12UEL5L", nil}, |
||||
{"a12uel5l", nil}, |
||||
{ |
||||
"an83characterlonghumanreadablepartthatcontainsthenumber1andtheexcludedcharactersbio1tt5tgs", |
||||
nil, |
||||
}, |
||||
{"abcdef1qpzry9x8gf2tvdw0s3jn54khce6mua7lmqqqxw", nil}, |
||||
{ |
||||
"11qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqc8247j", |
||||
nil, |
||||
}, |
||||
{"split1checkupstagehandshakeupstreamerranterredcaperred2y9e3w", nil}, |
||||
{ |
||||
"split1checkupstagehandshakeupstreamerranterredcaperred2y9e2w", |
||||
ErrInvalidChecksum{ |
||||
"2y9e3w", "2y9e3wlc445v", |
||||
"2y9e2w", |
||||
}, |
||||
}, // invalid checksum
|
||||
{ |
||||
"s lit1checkupstagehandshakeupstreamerranterredcaperredp8hs2p", |
||||
ErrInvalidCharacter(' '), |
||||
}, // invalid character (space) in hrp
|
||||
{ |
||||
"spl\x7Ft1checkupstagehandshakeupstreamerranterredcaperred2y9e3w", |
||||
ErrInvalidCharacter(127), |
||||
}, // invalid character (DEL) in hrp
|
||||
{ |
||||
"split1cheo2y9e2w", |
||||
ErrNonCharsetChar('o'), |
||||
}, // invalid character (o) in data part
|
||||
{"split1a2y9w", ErrInvalidSeparatorIndex(5)}, // too short data part
|
||||
{ |
||||
"1checkupstagehandshakeupstreamerranterredcaperred2y9e3w", |
||||
ErrInvalidSeparatorIndex(0), |
||||
}, // empty hrp
|
||||
{ |
||||
"11qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqsqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqc8247j", |
||||
ErrInvalidLength(91), |
||||
}, // too long
|
||||
// Additional test vectors used in bitcoin core
|
||||
{" 1nwldj5", ErrInvalidCharacter(' ')}, |
||||
{"\x7f" + "1axkwrx", ErrInvalidCharacter(0x7f)}, |
||||
{"\x801eym55h", ErrInvalidCharacter(0x80)}, |
||||
{ |
||||
"an84characterslonghumanreadablepartthatcontainsthenumber1andtheexcludedcharactersbio1569pvx", |
||||
ErrInvalidLength(91), |
||||
}, |
||||
{"pzry9x0s0muk", ErrInvalidSeparatorIndex(-1)}, |
||||
{"1pzry9x0s0muk", ErrInvalidSeparatorIndex(0)}, |
||||
{"x1b4n0q5v", ErrNonCharsetChar(98)}, |
||||
{"li1dgmt3", ErrInvalidSeparatorIndex(2)}, |
||||
{"de1lg7wt\xff", ErrInvalidCharacter(0xff)}, |
||||
{"A1G7SGD8", ErrInvalidChecksum{"2uel5l", "2uel5llqfn3a", "g7sgd8"}}, |
||||
{"10a06t8", ErrInvalidLength(7)}, |
||||
{"1qzzfhee", ErrInvalidSeparatorIndex(0)}, |
||||
{"a12UEL5L", ErrMixedCase{}}, |
||||
{"A12uEL5L", ErrMixedCase{}}, |
||||
} |
||||
for i, test := range tests { |
||||
str := []byte(test.str) |
||||
hrp, decoded, err := Decode([]byte(str)) |
||||
if !errors.Is(err, test.expectedError) { |
||||
t.Errorf( |
||||
"%d: expected decoding error %v "+ |
||||
"instead got %v", i, test.expectedError, err, |
||||
) |
||||
continue |
||||
} |
||||
if err != nil { |
||||
// End test case here if a decoding error was expected.
|
||||
continue |
||||
} |
||||
// Check that it encodes to the same string
|
||||
encoded, err := Encode(hrp, decoded) |
||||
if err != nil { |
||||
t.Errorf("encoding failed: %v", err) |
||||
} |
||||
if !utils.FastEqual(encoded, bytes.ToLower([]byte(str))) { |
||||
t.Errorf( |
||||
"expected data to encode to %v, but got %v", |
||||
str, encoded, |
||||
) |
||||
} |
||||
// Flip a bit in the string an make sure it is caught.
|
||||
pos := bytes.LastIndexAny(str, "1") |
||||
flipped := []byte(string(str[:pos+1]) + string(str[pos+1]^1) + string(str[pos+2:])) |
||||
_, _, err = Decode(flipped) |
||||
if err == nil { |
||||
t.Error("expected decoding to fail") |
||||
} |
||||
} |
||||
} |
||||
|
||||
// TestBech32M tests that the following set of strings, based on the test
|
||||
// vectors in BIP-350 are either valid or invalid using the new bech32m
|
||||
// checksum algo. Some of these strings are similar to the set of above test
|
||||
// vectors, but end up with different checksums.
|
||||
func TestBech32M(t *testing.T) { |
||||
tests := []struct { |
||||
str string |
||||
expectedError error |
||||
}{ |
||||
{"A1LQFN3A", nil}, |
||||
{"a1lqfn3a", nil}, |
||||
{ |
||||
"an83characterlonghumanreadablepartthatcontainsthetheexcludedcharactersbioandnumber11sg7hg6", |
||||
nil, |
||||
}, |
||||
{"abcdef1l7aum6echk45nj3s0wdvt2fg8x9yrzpqzd3ryx", nil}, |
||||
{ |
||||
"11llllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllludsr8", |
||||
nil, |
||||
}, |
||||
{"split1checkupstagehandshakeupstreamerranterredcaperredlc445v", nil}, |
||||
{"?1v759aa", nil}, |
||||
// Additional test vectors used in bitcoin core
|
||||
{"\x201xj0phk", ErrInvalidCharacter('\x20')}, |
||||
{"\x7f1g6xzxy", ErrInvalidCharacter('\x7f')}, |
||||
{"\x801vctc34", ErrInvalidCharacter('\x80')}, |
||||
{ |
||||
"an84characterslonghumanreadablepartthatcontainsthetheexcludedcharactersbioandnumber11d6pts4", |
||||
ErrInvalidLength(91), |
||||
}, |
||||
{"qyrz8wqd2c9m", ErrInvalidSeparatorIndex(-1)}, |
||||
{"1qyrz8wqd2c9m", ErrInvalidSeparatorIndex(0)}, |
||||
{"y1b0jsk6g", ErrNonCharsetChar(98)}, |
||||
{"lt1igcx5c0", ErrNonCharsetChar(105)}, |
||||
{"in1muywd", ErrInvalidSeparatorIndex(2)}, |
||||
{"mm1crxm3i", ErrNonCharsetChar(105)}, |
||||
{"au1s5cgom", ErrNonCharsetChar(111)}, |
||||
{"M1VUXWEZ", ErrInvalidChecksum{"mzl49c", "mzl49cw70eq6", "vuxwez"}}, |
||||
{"16plkw9", ErrInvalidLength(7)}, |
||||
{"1p2gdwpf", ErrInvalidSeparatorIndex(0)}, |
||||
|
||||
{" 1nwldj5", ErrInvalidCharacter(' ')}, |
||||
{"\x7f" + "1axkwrx", ErrInvalidCharacter(0x7f)}, |
||||
{"\x801eym55h", ErrInvalidCharacter(0x80)}, |
||||
} |
||||
for i, test := range tests { |
||||
str := []byte(test.str) |
||||
hrp, decoded, err := Decode(str) |
||||
if test.expectedError != err { |
||||
t.Errorf( |
||||
"%d: (%v) expected decoding error %v "+ |
||||
"instead got %v", i, str, test.expectedError, |
||||
err, |
||||
) |
||||
continue |
||||
} |
||||
if err != nil { |
||||
// End test case here if a decoding error was expected.
|
||||
continue |
||||
} |
||||
// Check that it encodes to the same string, using bech32 m.
|
||||
encoded, err := EncodeM(hrp, decoded) |
||||
if err != nil { |
||||
t.Errorf("encoding failed: %v", err) |
||||
} |
||||
|
||||
if !utils.FastEqual(encoded, bytes.ToLower(str)) { |
||||
t.Errorf( |
||||
"expected data to encode to %v, but got %v", |
||||
str, encoded, |
||||
) |
||||
} |
||||
// Flip a bit in the string an make sure it is caught.
|
||||
pos := bytes.LastIndexAny(str, "1") |
||||
flipped := []byte(string(str[:pos+1]) + string(str[pos+1]^1) + string(str[pos+2:])) |
||||
_, _, err = Decode(flipped) |
||||
if err == nil { |
||||
t.Error("expected decoding to fail") |
||||
} |
||||
} |
||||
} |
||||
|
||||
// TestBech32DecodeGeneric tests that given a bech32 string, or a bech32m
|
||||
// string, the proper checksum version is returned so that callers can perform
|
||||
// segwit addr validation.
|
||||
func TestBech32DecodeGeneric(t *testing.T) { |
||||
tests := []struct { |
||||
str string |
||||
version Version |
||||
}{ |
||||
{"A1LQFN3A", VersionM}, |
||||
{"a1lqfn3a", VersionM}, |
||||
{ |
||||
"an83characterlonghumanreadablepartthatcontainsthetheexcludedcharactersbioandnumber11sg7hg6", |
||||
VersionM, |
||||
}, |
||||
{"abcdef1l7aum6echk45nj3s0wdvt2fg8x9yrzpqzd3ryx", VersionM}, |
||||
{ |
||||
"11llllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllludsr8", |
||||
VersionM, |
||||
}, |
||||
{ |
||||
"split1checkupstagehandshakeupstreamerranterredcaperredlc445v", |
||||
VersionM, |
||||
}, |
||||
{"?1v759aa", VersionM}, |
||||
{"A12UEL5L", Version0}, |
||||
{"a12uel5l", Version0}, |
||||
{ |
||||
"an83characterlonghumanreadablepartthatcontainsthenumber1andtheexcludedcharactersbio1tt5tgs", |
||||
Version0, |
||||
}, |
||||
{"abcdef1qpzry9x8gf2tvdw0s3jn54khce6mua7lmqqqxw", Version0}, |
||||
{ |
||||
"11qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqc8247j", |
||||
Version0, |
||||
}, |
||||
{ |
||||
"split1checkupstagehandshakeupstreamerranterredcaperred2y9e3w", |
||||
Version0, |
||||
}, |
||||
{"BC1QW508D6QEJXTDG4Y5R3ZARVARY0C5XW7KV8F3T4", Version0}, |
||||
{ |
||||
"tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7", |
||||
Version0, |
||||
}, |
||||
{ |
||||
"bc1pw508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7kt5nd6y", |
||||
VersionM, |
||||
}, |
||||
{"BC1SW50QGDZ25J", VersionM}, |
||||
{"bc1zw508d6qejxtdg4y5r3zarvaryvaxxpcs", VersionM}, |
||||
{ |
||||
"tb1qqqqqp399et2xygdj5xreqhjjvcmzhxw4aywxecjdzew6hylgvsesrxh6hy", |
||||
Version0, |
||||
}, |
||||
{ |
||||
"tb1pqqqqp399et2xygdj5xreqhjjvcmzhxw4aywxecjdzew6hylgvsesf3hn0c", |
||||
VersionM, |
||||
}, |
||||
{ |
||||
"bc1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vqzk5jj0", |
||||
VersionM, |
||||
}, |
||||
} |
||||
for i, test := range tests { |
||||
_, _, version, err := DecodeGeneric([]byte(test.str)) |
||||
if err != nil { |
||||
t.Errorf( |
||||
"%d: (%v) unexpected error during "+ |
||||
"decoding: %v", i, test.str, err, |
||||
) |
||||
continue |
||||
} |
||||
if version != test.version { |
||||
t.Errorf( |
||||
"(%v): invalid version: expected %v, got %v", |
||||
test.str, test.version, version, |
||||
) |
||||
} |
||||
} |
||||
} |
||||
|
||||
// TestMixedCaseEncode ensures mixed case HRPs are converted to lowercase as
|
||||
// expected when encoding and that decoding the produced encoding when converted
|
||||
// to all uppercase produces the lowercase HRP and original data.
|
||||
func TestMixedCaseEncode(t *testing.T) { |
||||
tests := []struct { |
||||
name string |
||||
hrp string |
||||
data string |
||||
encoded string |
||||
}{ |
||||
{ |
||||
name: "all uppercase HRP with no data", |
||||
hrp: "A", |
||||
data: "", |
||||
encoded: "a12uel5l", |
||||
}, { |
||||
name: "all uppercase HRP with data", |
||||
hrp: "UPPERCASE", |
||||
data: "787878", |
||||
encoded: "uppercase10pu8sss7kmp", |
||||
}, { |
||||
name: "mixed case HRP even offsets uppercase", |
||||
hrp: "AbCdEf", |
||||
data: "00443214c74254b635cf84653a56d7c675be77df", |
||||
encoded: "abcdef1qpzry9x8gf2tvdw0s3jn54khce6mua7lmqqqxw", |
||||
}, { |
||||
name: "mixed case HRP odd offsets uppercase ", |
||||
hrp: "aBcDeF", |
||||
data: "00443214c74254b635cf84653a56d7c675be77df", |
||||
encoded: "abcdef1qpzry9x8gf2tvdw0s3jn54khce6mua7lmqqqxw", |
||||
}, { |
||||
name: "all lowercase HRP", |
||||
hrp: "abcdef", |
||||
data: "00443214c74254b635cf84653a56d7c675be77df", |
||||
encoded: "abcdef1qpzry9x8gf2tvdw0s3jn54khce6mua7lmqqqxw", |
||||
}, |
||||
} |
||||
for _, test := range tests { |
||||
// Convert the text hex to bytes, convert those bytes from base256 to
|
||||
// base32, then ensure the encoded result with the HRP provided in the
|
||||
// test data is as expected.
|
||||
data, err := hex.DecodeString(test.data) |
||||
if err != nil { |
||||
t.Errorf("%q: invalid hex %q: %v", test.name, test.data, err) |
||||
continue |
||||
} |
||||
convertedData, err := ConvertBits(data, 8, 5, true) |
||||
if err != nil { |
||||
t.Errorf( |
||||
"%q: unexpected convert bits error: %v", test.name, |
||||
err, |
||||
) |
||||
continue |
||||
} |
||||
gotEncoded, err := Encode([]byte(test.hrp), convertedData) |
||||
if err != nil { |
||||
t.Errorf("%q: unexpected encode error: %v", test.name, err) |
||||
continue |
||||
} |
||||
if !utils.FastEqual(gotEncoded, []byte(test.encoded)) { |
||||
t.Errorf( |
||||
"%q: mismatched encoding -- got %q, want %q", test.name, |
||||
gotEncoded, test.encoded, |
||||
) |
||||
continue |
||||
} |
||||
// Ensure the decoding the expected lowercase encoding converted to all
|
||||
// uppercase produces the lowercase HRP and original data.
|
||||
gotHRP, gotData, err := Decode(bytes.ToUpper([]byte(test.encoded))) |
||||
if err != nil { |
||||
t.Errorf("%q: unexpected decode error: %v", test.name, err) |
||||
continue |
||||
} |
||||
wantHRP := strings.ToLower(test.hrp) |
||||
if !utils.FastEqual(gotHRP, []byte(wantHRP)) { |
||||
t.Errorf( |
||||
"%q: mismatched decoded HRP -- got %q, want %q", test.name, |
||||
gotHRP, wantHRP, |
||||
) |
||||
continue |
||||
} |
||||
convertedGotData, err := ConvertBits(gotData, 5, 8, false) |
||||
if err != nil { |
||||
t.Errorf( |
||||
"%q: unexpected convert bits error: %v", test.name, |
||||
err, |
||||
) |
||||
continue |
||||
} |
||||
if !utils.FastEqual(convertedGotData, data) { |
||||
t.Errorf( |
||||
"%q: mismatched data -- got %x, want %x", test.name, |
||||
convertedGotData, data, |
||||
) |
||||
continue |
||||
} |
||||
} |
||||
} |
||||
|
||||
// TestCanDecodeUnlimtedBech32 tests whether decoding a large bech32 string works
|
||||
// when using the DecodeNoLimit version
|
||||
func TestCanDecodeUnlimtedBech32(t *testing.T) { |
||||
input := "11qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqsqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq5kx0yd" |
||||
// Sanity check that an input of this length errors on regular Decode()
|
||||
_, _, err := Decode([]byte(input)) |
||||
if err == nil { |
||||
t.Fatalf("Test vector not appropriate") |
||||
} |
||||
// Try and decode it.
|
||||
hrp, data, err := DecodeNoLimit([]byte(input)) |
||||
if err != nil { |
||||
t.Fatalf( |
||||
"Expected decoding of large string to work. Got error: %v", |
||||
err, |
||||
) |
||||
} |
||||
// Verify data for correctness.
|
||||
if !utils.FastEqual(hrp, []byte("1")) { |
||||
t.Fatalf("Unexpected hrp: %v", hrp) |
||||
} |
||||
decodedHex := fmt.Sprintf("%x", data) |
||||
expected := "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000" |
||||
if decodedHex != expected { |
||||
t.Fatalf("Unexpected decoded data: %s", decodedHex) |
||||
} |
||||
} |
||||
|
||||
// TestBech32Base256 ensures decoding and encoding various bech32, HRPs, and
|
||||
// data produces the expected results when using EncodeFromBase256 and
|
||||
// DecodeToBase256. It includes tests for proper handling of case
|
||||
// manipulations.
|
||||
func TestBech32Base256(t *testing.T) { |
||||
tests := []struct { |
||||
name string // test name
|
||||
encoded string // bech32 string to decode
|
||||
hrp string // expected human-readable part
|
||||
data string // expected hex-encoded data
|
||||
err error // expected error
|
||||
}{ |
||||
{ |
||||
name: "all uppercase, no data", |
||||
encoded: "A12UEL5L", |
||||
hrp: "a", |
||||
data: "", |
||||
}, { |
||||
name: "long hrp with separator and excluded chars, no data", |
||||
encoded: "an83characterlonghumanreadablepartthatcontainsthenumber1andtheexcludedcharactersbio1tt5tgs", |
||||
hrp: "an83characterlonghumanreadablepartthatcontainsthenumber1andtheexcludedcharactersbio", |
||||
data: "", |
||||
}, { |
||||
name: "6 char hrp with data with leading zero", |
||||
encoded: "abcdef1qpzry9x8gf2tvdw0s3jn54khce6mua7lmqqqxw", |
||||
hrp: "abcdef", |
||||
data: "00443214c74254b635cf84653a56d7c675be77df", |
||||
}, { |
||||
name: "hrp same as separator and max length encoded string", |
||||
encoded: "11qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqc8247j", |
||||
hrp: "1", |
||||
data: "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", |
||||
}, { |
||||
name: "5 char hrp with data chosen to produce human-readable data part", |
||||
encoded: "split1checkupstagehandshakeupstreamerranterredcaperred2y9e3w", |
||||
hrp: "split", |
||||
data: "c5f38b70305f519bf66d85fb6cf03058f3dde463ecd7918f2dc743918f2d", |
||||
}, { |
||||
name: "same as previous but with checksum invalidated", |
||||
encoded: "split1checkupstagehandshakeupstreamerranterredcaperred2y9e2w", |
||||
err: ErrInvalidChecksum{"2y9e3w", "2y9e3wlc445v", "2y9e2w"}, |
||||
}, { |
||||
name: "hrp with invalid character (space)", |
||||
encoded: "s lit1checkupstagehandshakeupstreamerranterredcaperredp8hs2p", |
||||
err: ErrInvalidCharacter(' '), |
||||
}, { |
||||
name: "hrp with invalid character (DEL)", |
||||
encoded: "spl\x7ft1checkupstagehandshakeupstreamerranterredcaperred2y9e3w", |
||||
err: ErrInvalidCharacter(127), |
||||
}, { |
||||
name: "data part with invalid character (o)", |
||||
encoded: "split1cheo2y9e2w", |
||||
err: ErrNonCharsetChar('o'), |
||||
}, { |
||||
name: "data part too short", |
||||
encoded: "split1a2y9w", |
||||
err: ErrInvalidSeparatorIndex(5), |
||||
}, { |
||||
name: "empty hrp", |
||||
encoded: "1checkupstagehandshakeupstreamerranterredcaperred2y9e3w", |
||||
err: ErrInvalidSeparatorIndex(0), |
||||
}, { |
||||
name: "no separator", |
||||
encoded: "pzry9x0s0muk", |
||||
err: ErrInvalidSeparatorIndex(-1), |
||||
}, { |
||||
name: "too long by one char", |
||||
encoded: "11qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqsqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqc8247j", |
||||
err: ErrInvalidLength(91), |
||||
}, { |
||||
name: "invalid due to mixed case in hrp", |
||||
encoded: "aBcdef1qpzry9x8gf2tvdw0s3jn54khce6mua7lmqqqxw", |
||||
err: ErrMixedCase{}, |
||||
}, { |
||||
name: "invalid due to mixed case in data part", |
||||
encoded: "abcdef1Qpzry9x8gf2tvdw0s3jn54khce6mua7lmqqqxw", |
||||
err: ErrMixedCase{}, |
||||
}, |
||||
} |
||||
for _, test := range tests { |
||||
// Ensure the decode either produces an error or not as expected.
|
||||
str := test.encoded |
||||
gotHRP, gotData, err := DecodeToBase256([]byte(str)) |
||||
if test.err != err { |
||||
t.Errorf( |
||||
"%q: unexpected decode error -- got %v, want %v", |
||||
test.name, err, test.err, |
||||
) |
||||
continue |
||||
} |
||||
if err != nil { |
||||
// End test case here if a decoding error was expected.
|
||||
continue |
||||
} |
||||
// Ensure the expected HRP and original data are as expected.
|
||||
if !utils.FastEqual(gotHRP, []byte(test.hrp)) { |
||||
t.Errorf( |
||||
"%q: mismatched decoded HRP -- got %q, want %q", test.name, |
||||
gotHRP, test.hrp, |
||||
) |
||||
continue |
||||
} |
||||
data, err := hex.DecodeString(test.data) |
||||
if err != nil { |
||||
t.Errorf("%q: invalid hex %q: %v", test.name, test.data, err) |
||||
continue |
||||
} |
||||
if !utils.FastEqual(gotData, data) { |
||||
t.Errorf( |
||||
"%q: mismatched data -- got %x, want %x", test.name, |
||||
gotData, data, |
||||
) |
||||
continue |
||||
} |
||||
// Encode the same data with the HRP converted to all uppercase and
|
||||
// ensure the result is the lowercase version of the original encoded
|
||||
// bech32 string.
|
||||
gotEncoded, err := EncodeFromBase256( |
||||
bytes.ToUpper([]byte(test.hrp)), data, |
||||
) |
||||
if err != nil { |
||||
t.Errorf( |
||||
"%q: unexpected uppercase HRP encode error: %v", test.name, |
||||
err, |
||||
) |
||||
} |
||||
wantEncoded := bytes.ToLower([]byte(str)) |
||||
if !utils.FastEqual(gotEncoded, wantEncoded) { |
||||
t.Errorf( |
||||
"%q: mismatched encoding -- got %q, want %q", test.name, |
||||
gotEncoded, wantEncoded, |
||||
) |
||||
} |
||||
// Encode the same data with the HRP converted to all lowercase and
|
||||
// ensure the result is the lowercase version of the original encoded
|
||||
// bech32 string.
|
||||
gotEncoded, err = EncodeFromBase256( |
||||
bytes.ToLower([]byte(test.hrp)), data, |
||||
) |
||||
if err != nil { |
||||
t.Errorf( |
||||
"%q: unexpected lowercase HRP encode error: %v", test.name, |
||||
err, |
||||
) |
||||
} |
||||
if !utils.FastEqual(gotEncoded, wantEncoded) { |
||||
t.Errorf( |
||||
"%q: mismatched encoding -- got %q, want %q", test.name, |
||||
gotEncoded, wantEncoded, |
||||
) |
||||
} |
||||
// Encode the same data with the HRP converted to mixed upper and
|
||||
// lowercase and ensure the result is the lowercase version of the
|
||||
// original encoded bech32 string.
|
||||
var mixedHRPBuilder bytes.Buffer |
||||
for i, r := range test.hrp { |
||||
if i%2 == 0 { |
||||
mixedHRPBuilder.WriteString(strings.ToUpper(string(r))) |
||||
continue |
||||
} |
||||
mixedHRPBuilder.WriteRune(r) |
||||
} |
||||
gotEncoded, err = EncodeFromBase256(mixedHRPBuilder.Bytes(), data) |
||||
if err != nil { |
||||
t.Errorf( |
||||
"%q: unexpected lowercase HRP encode error: %v", test.name, |
||||
err, |
||||
) |
||||
} |
||||
if !utils.FastEqual(gotEncoded, wantEncoded) { |
||||
t.Errorf( |
||||
"%q: mismatched encoding -- got %q, want %q", test.name, |
||||
gotEncoded, wantEncoded, |
||||
) |
||||
} |
||||
// Ensure a bit flip in the string is caught.
|
||||
pos := strings.LastIndexAny(test.encoded, "1") |
||||
flipped := str[:pos+1] + string(str[pos+1]^1) + str[pos+2:] |
||||
_, _, err = DecodeToBase256([]byte(flipped)) |
||||
if err == nil { |
||||
t.Error("expected decoding to fail") |
||||
} |
||||
} |
||||
} |
||||
|
||||
// BenchmarkEncodeDecodeCycle performs a benchmark for a full encode/decode
|
||||
// cycle of a bech32 string. It also reports the allocation count, which we
|
||||
// expect to be 2 for a fully optimized cycle.
|
||||
func BenchmarkEncodeDecodeCycle(b *testing.B) { |
||||
// Use a fixed, 49-byte raw data for testing.
|
||||
inputData, err := hex.DecodeString("cbe6365ddbcda9a9915422c3f091c13f8c7b2f263b8d34067bd12c274408473fa764871c9dd51b1bb34873b3473b633ed1") |
||||
if err != nil { |
||||
b.Fatalf("failed to initialize input data: %v", err) |
||||
} |
||||
// Convert this into a 79-byte, base 32 byte slice.
|
||||
base32Input, err := ConvertBits(inputData, 8, 5, true) |
||||
if err != nil { |
||||
b.Fatalf("failed to convert input to 32 bits-per-element: %v", err) |
||||
} |
||||
// Use a fixed hrp for the tests. This should generate an encoded bech32
|
||||
// string of size 90 (the maximum allowed by BIP-173).
|
||||
hrp := "bc" |
||||
// Begin the benchmark. Given that we test one roundtrip per iteration
|
||||
// (that is, one Encode() and one Decode() operation), we expect at most
|
||||
// 2 allocations per reported test op.
|
||||
b.ReportAllocs() |
||||
b.ResetTimer() |
||||
for i := 0; i < b.N; i++ { |
||||
str, err := Encode([]byte(hrp), base32Input) |
||||
if err != nil { |
||||
b.Fatalf("failed to encode input: %v", err) |
||||
} |
||||
_, _, err = Decode(str) |
||||
if err != nil { |
||||
b.Fatalf("failed to decode string: %v", err) |
||||
} |
||||
} |
||||
} |
||||
|
||||
// TestConvertBits tests whether base conversion works using TestConvertBits().
|
||||
func TestConvertBits(t *testing.T) { |
||||
tests := []struct { |
||||
input string |
||||
output string |
||||
fromBits uint8 |
||||
toBits uint8 |
||||
pad bool |
||||
}{ |
||||
// Trivial empty conversions.
|
||||
{"", "", 8, 5, false}, |
||||
{"", "", 8, 5, true}, |
||||
{"", "", 5, 8, false}, |
||||
{"", "", 5, 8, true}, |
||||
// Conversions of 0 value with/without padding.
|
||||
{"00", "00", 8, 5, false}, |
||||
{"00", "0000", 8, 5, true}, |
||||
{"0000", "00", 5, 8, false}, |
||||
{"0000", "0000", 5, 8, true}, |
||||
// Testing when conversion ends exactly at the byte edge. This makes
|
||||
// both padded and unpadded versions the same.
|
||||
{"0000000000", "0000000000000000", 8, 5, false}, |
||||
{"0000000000", "0000000000000000", 8, 5, true}, |
||||
{"0000000000000000", "0000000000", 5, 8, false}, |
||||
{"0000000000000000", "0000000000", 5, 8, true}, |
||||
// Conversions of full byte sequences.
|
||||
{"ffffff", "1f1f1f1f1e", 8, 5, true}, |
||||
{"1f1f1f1f1e", "ffffff", 5, 8, false}, |
||||
{"1f1f1f1f1e", "ffffff00", 5, 8, true}, |
||||
// Sample random conversions.
|
||||
{"c9ca", "190705", 8, 5, false}, |
||||
{"c9ca", "19070500", 8, 5, true}, |
||||
{"19070500", "c9ca", 5, 8, false}, |
||||
{"19070500", "c9ca00", 5, 8, true}, |
||||
// Test cases tested on TestConvertBitsFailures with their corresponding
|
||||
// fixes.
|
||||
{"ff", "1f1c", 8, 5, true}, |
||||
{"1f1c10", "ff20", 5, 8, true}, |
||||
// Large conversions.
|
||||
{ |
||||
"cbe6365ddbcda9a9915422c3f091c13f8c7b2f263b8d34067bd12c274408473fa764871c9dd51b1bb34873b3473b633ed1", |
||||
"190f13030c170e1b1916141a13040a14040b011f01040e01071e0607160b1906070e06130801131b1a0416020e110008081c1f1a0e19040703120e1d0a06181b160d0407070c1a07070d11131d1408", |
||||
8, 5, true, |
||||
}, |
||||
{ |
||||
"190f13030c170e1b1916141a13040a14040b011f01040e01071e0607160b1906070e06130801131b1a0416020e110008081c1f1a0e19040703120e1d0a06181b160d0407070c1a07070d11131d1408", |
||||
"cbe6365ddbcda9a9915422c3f091c13f8c7b2f263b8d34067bd12c274408473fa764871c9dd51b1bb34873b3473b633ed100", |
||||
5, 8, true, |
||||
}, |
||||
} |
||||
for i, tc := range tests { |
||||
input, err := hex.DecodeString(tc.input) |
||||
if err != nil { |
||||
t.Fatalf("invalid test input data: %v", err) |
||||
} |
||||
expected, err := hex.DecodeString(tc.output) |
||||
if err != nil { |
||||
t.Fatalf("invalid test output data: %v", err) |
||||
} |
||||
actual, err := ConvertBits(input, tc.fromBits, tc.toBits, tc.pad) |
||||
if err != nil { |
||||
t.Fatalf("test case %d failed: %v", i, err) |
||||
} |
||||
if !utils.FastEqual(actual, expected) { |
||||
t.Fatalf( |
||||
"test case %d has wrong output; expected=%x actual=%x", |
||||
i, expected, actual, |
||||
) |
||||
} |
||||
} |
||||
} |
||||
|
||||
// TestConvertBitsFailures tests for the expected conversion failures of
|
||||
// ConvertBits().
|
||||
func TestConvertBitsFailures(t *testing.T) { |
||||
tests := []struct { |
||||
input string |
||||
fromBits uint8 |
||||
toBits uint8 |
||||
pad bool |
||||
err error |
||||
}{ |
||||
// Not enough output bytes when not using padding.
|
||||
{"ff", 8, 5, false, ErrInvalidIncompleteGroup{}}, |
||||
{"1f1c10", 5, 8, false, ErrInvalidIncompleteGroup{}}, |
||||
// Unsupported bit conversions.
|
||||
{"", 0, 5, false, ErrInvalidBitGroups{}}, |
||||
{"", 10, 5, false, ErrInvalidBitGroups{}}, |
||||
{"", 5, 0, false, ErrInvalidBitGroups{}}, |
||||
{"", 5, 10, false, ErrInvalidBitGroups{}}, |
||||
} |
||||
for i, tc := range tests { |
||||
input, err := hex.DecodeString(tc.input) |
||||
if err != nil { |
||||
t.Fatalf("invalid test input data: %v", err) |
||||
} |
||||
_, err = ConvertBits(input, tc.fromBits, tc.toBits, tc.pad) |
||||
if err != tc.err { |
||||
t.Fatalf( |
||||
"test case %d failure: expected '%v' got '%v'", i, |
||||
tc.err, err, |
||||
) |
||||
} |
||||
} |
||||
} |
||||
|
||||
// BenchmarkConvertBitsDown benchmarks the speed and memory allocation behavior
|
||||
// of ConvertBits when converting from a higher base into a lower base (e.g. 8
|
||||
// => 5).
|
||||
//
|
||||
// Only a single allocation is expected, which is used for the output array.
|
||||
func BenchmarkConvertBitsDown(b *testing.B) { |
||||
// Use a fixed, 49-byte raw data for testing.
|
||||
inputData, err := hex.DecodeString("cbe6365ddbcda9a9915422c3f091c13f8c7b2f263b8d34067bd12c274408473fa764871c9dd51b1bb34873b3473b633ed1") |
||||
if err != nil { |
||||
b.Fatalf("failed to initialize input data: %v", err) |
||||
} |
||||
b.ReportAllocs() |
||||
b.ResetTimer() |
||||
for i := 0; i < b.N; i++ { |
||||
_, err := ConvertBits(inputData, 8, 5, true) |
||||
if err != nil { |
||||
b.Fatalf("error converting bits: %v", err) |
||||
} |
||||
} |
||||
} |
||||
|
||||
// BenchmarkConvertBitsDown benchmarks the speed and memory allocation behavior
|
||||
// of ConvertBits when converting from a lower base into a higher base (e.g. 5
|
||||
// => 8).
|
||||
//
|
||||
// Only a single allocation is expected, which is used for the output array.
|
||||
func BenchmarkConvertBitsUp(b *testing.B) { |
||||
// Use a fixed, 79-byte raw data for testing.
|
||||
inputData, err := hex.DecodeString("190f13030c170e1b1916141a13040a14040b011f01040e01071e0607160b1906070e06130801131b1a0416020e110008081c1f1a0e19040703120e1d0a06181b160d0407070c1a07070d11131d1408") |
||||
if err != nil { |
||||
b.Fatalf("failed to initialize input data: %v", err) |
||||
} |
||||
b.ReportAllocs() |
||||
b.ResetTimer() |
||||
for i := 0; i < b.N; i++ { |
||||
_, err := ConvertBits(inputData, 8, 5, true) |
||||
if err != nil { |
||||
b.Fatalf("error converting bits: %v", err) |
||||
} |
||||
} |
||||
} |
||||
@ -1,13 +0,0 @@
@@ -1,13 +0,0 @@
|
||||
// Copyright (c) 2017 The btcsuite developers
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package bech32 provides a Go implementation of the bech32 format specified in
|
||||
// BIP 173.
|
||||
//
|
||||
// Bech32 strings consist of a human-readable part (hrp), followed by the
|
||||
// separator 1, then a checksummed data part encoded using the 32 characters
|
||||
// "qpzry9x8gf2tvdw0s3jn54khce6mua7l".
|
||||
//
|
||||
// More info: https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki
|
||||
package bech32 |
||||
@ -1,89 +0,0 @@
@@ -1,89 +0,0 @@
|
||||
// Copyright (c) 2019 The Decred developers
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package bech32 |
||||
|
||||
import ( |
||||
"fmt" |
||||
) |
||||
|
||||
// ErrMixedCase is returned when the bech32 string has both lower and uppercase
|
||||
// characters.
|
||||
type ErrMixedCase struct{} |
||||
|
||||
func (err ErrMixedCase) Error() string { |
||||
return "string not all lowercase or all uppercase" |
||||
} |
||||
|
||||
// ErrInvalidBitGroups is returned when conversion is attempted between byte
|
||||
// slices using bit-per-element of unsupported value.
|
||||
type ErrInvalidBitGroups struct{} |
||||
|
||||
func (err ErrInvalidBitGroups) Error() string { |
||||
return "only bit groups between 1 and 8 allowed" |
||||
} |
||||
|
||||
// ErrInvalidIncompleteGroup is returned when then byte slice used as input has
|
||||
// data of wrong length.
|
||||
type ErrInvalidIncompleteGroup struct{} |
||||
|
||||
func (err ErrInvalidIncompleteGroup) Error() string { |
||||
return "invalid incomplete group" |
||||
} |
||||
|
||||
// ErrInvalidLength is returned when the bech32 string has an invalid length
|
||||
// given the BIP-173 defined restrictions.
|
||||
type ErrInvalidLength int |
||||
|
||||
func (err ErrInvalidLength) Error() string { |
||||
return fmt.Sprintf("invalid bech32 string length %d", int(err)) |
||||
} |
||||
|
||||
// ErrInvalidCharacter is returned when the bech32 string has a character
|
||||
// outside the range of the supported charset.
|
||||
type ErrInvalidCharacter rune |
||||
|
||||
func (err ErrInvalidCharacter) Error() string { |
||||
return fmt.Sprintf("invalid character in string: '%c'", rune(err)) |
||||
} |
||||
|
||||
// ErrInvalidSeparatorIndex is returned when the separator character '1' is
|
||||
// in an invalid position in the bech32 string.
|
||||
type ErrInvalidSeparatorIndex int |
||||
|
||||
func (err ErrInvalidSeparatorIndex) Error() string { |
||||
return fmt.Sprintf("invalid separator index %d", int(err)) |
||||
} |
||||
|
||||
// ErrNonCharsetChar is returned when a character outside of the specific
|
||||
// bech32 charset is used in the string.
|
||||
type ErrNonCharsetChar rune |
||||
|
||||
func (err ErrNonCharsetChar) Error() string { |
||||
return fmt.Sprintf("invalid character not part of charset: %v", int(err)) |
||||
} |
||||
|
||||
// ErrInvalidChecksum is returned when the extracted checksum of the string
|
||||
// is different than what was expected. Both the original version, as well as
|
||||
// the new bech32m checksum may be specified.
|
||||
type ErrInvalidChecksum struct { |
||||
Expected string |
||||
ExpectedM string |
||||
Actual string |
||||
} |
||||
|
||||
func (err ErrInvalidChecksum) Error() string { |
||||
return fmt.Sprintf( |
||||
"invalid checksum (expected (bech32=%v, "+ |
||||
"bech32m=%v), got %v)", err.Expected, err.ExpectedM, err.Actual, |
||||
) |
||||
} |
||||
|
||||
// ErrInvalidDataByte is returned when a byte outside the range required for
|
||||
// conversion into a string was found.
|
||||
type ErrInvalidDataByte byte |
||||
|
||||
func (err ErrInvalidDataByte) Error() string { |
||||
return fmt.Sprintf("invalid data byte: %v", byte(err)) |
||||
} |
||||
@ -1,43 +0,0 @@
@@ -1,43 +0,0 @@
|
||||
// Copyright (c) 2017 The btcsuite developers
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package bech32 |
||||
|
||||
import ( |
||||
"encoding/hex" |
||||
"fmt" |
||||
) |
||||
|
||||
// This example demonstrates how to decode a bech32 encoded string.
|
||||
func ExampleDecode() { |
||||
encoded := "bc1pw508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7k7grplx" |
||||
hrp, decoded, err := Decode([]byte(encoded)) |
||||
if err != nil { |
||||
fmt.Println("Error:", err) |
||||
} |
||||
// Show the decoded data.
|
||||
fmt.Printf("Decoded human-readable part: %s\n", hrp) |
||||
fmt.Println("Decoded Data:", hex.EncodeToString(decoded)) |
||||
// Output:
|
||||
// Decoded human-readable part: bc
|
||||
// Decoded Data: 010e140f070d1a001912060b0d081504140311021d030c1d03040f1814060e1e160e140f070d1a001912060b0d081504140311021d030c1d03040f1814060e1e16
|
||||
} |
||||
|
||||
// This example demonstrates how to encode data into a bech32 string.
|
||||
func ExampleEncode() { |
||||
data := []byte("Test data") |
||||
// Convert test data to base32:
|
||||
conv, err := ConvertBits(data, 8, 5, true) |
||||
if err != nil { |
||||
fmt.Println("Error:", err) |
||||
} |
||||
encoded, err := Encode([]byte("customHrp!11111q"), conv) |
||||
if err != nil { |
||||
fmt.Println("Error:", err) |
||||
} |
||||
// Show the encoded data.
|
||||
fmt.Printf("Encoded Data: %s", encoded) |
||||
// Output:
|
||||
// Encoded Data: customhrp!11111q123jhxapqv3shgcgkxpuhe
|
||||
} |
||||
@ -1,40 +0,0 @@
@@ -1,40 +0,0 @@
|
||||
package bech32 |
||||
|
||||
// ChecksumConst is a type that represents the currently defined bech32
|
||||
// checksum constants.
|
||||
type ChecksumConst int |
||||
|
||||
const ( |
||||
// Version0Const is the original constant used in the checksum
|
||||
// verification for bech32.
|
||||
Version0Const ChecksumConst = 1 |
||||
// VersionMConst is the new constant used for bech32m checksum
|
||||
// verification.
|
||||
VersionMConst ChecksumConst = 0x2bc830a3 |
||||
) |
||||
|
||||
// Version defines the current set of bech32 versions.
|
||||
type Version uint8 |
||||
|
||||
const ( |
||||
// Version0 defines the original bech version.
|
||||
Version0 Version = iota |
||||
// VersionM is the new bech32 version defined in BIP-350, also known as
|
||||
// bech32m.
|
||||
VersionM |
||||
// VersionUnknown denotes an unknown bech version.
|
||||
VersionUnknown |
||||
) |
||||
|
||||
// VersionToConsts maps bech32 versions to the checksum constant to be used
|
||||
// when encoding, and asserting a particular version when decoding.
|
||||
var VersionToConsts = map[Version]ChecksumConst{ |
||||
Version0: Version0Const, |
||||
VersionM: VersionMConst, |
||||
} |
||||
|
||||
// ConstsToVersion maps a bech32 constant to the version it's associated with.
|
||||
var ConstsToVersion = map[ChecksumConst]Version{ |
||||
Version0Const: Version0, |
||||
VersionMConst: VersionM, |
||||
} |
||||
@ -1,188 +0,0 @@
@@ -1,188 +0,0 @@
|
||||
// Copyright 2013-2016 The btcsuite developers
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package btcec |
||||
|
||||
import ( |
||||
"math/big" |
||||
"testing" |
||||
|
||||
"next.orly.dev/pkg/crypto/ec/secp256k1" |
||||
"next.orly.dev/pkg/encoders/hex" |
||||
) |
||||
|
||||
// setHex decodes the passed big-endian hex string into the internal field value
|
||||
// representation. Only the first 32-bytes are used.
|
||||
//
|
||||
// This is NOT constant time.
|
||||
//
|
||||
// The field value is returned to support chaining. This enables syntax like:
|
||||
// f := new(FieldVal).SetHex("0abc").Add(1) so that f = 0x0abc + 1
|
||||
func setHex(hexString string) *FieldVal { |
||||
if len(hexString)%2 != 0 { |
||||
hexString = "0" + hexString |
||||
} |
||||
bytes, _ := hex.Dec(hexString) |
||||
var f FieldVal |
||||
f.SetByteSlice(bytes) |
||||
return &f |
||||
} |
||||
|
||||
// hexToFieldVal converts the passed hex string into a FieldVal and will panic
|
||||
// if there is an error. This is only provided for the hard-coded constants so
|
||||
// errors in the source code can be detected. It will only (and must only) be
|
||||
// called with hard-coded values.
|
||||
func hexToFieldVal(s string) *FieldVal { |
||||
b, err := hex.Dec(s) |
||||
if err != nil { |
||||
panic("invalid hex in source file: " + s) |
||||
} |
||||
var f FieldVal |
||||
if overflow := f.SetByteSlice(b); overflow { |
||||
panic("hex in source file overflows mod P: " + s) |
||||
} |
||||
return &f |
||||
} |
||||
|
||||
// fromHex converts the passed hex string into a big integer pointer and will
|
||||
// panic is there is an error. This is only provided for the hard-coded
|
||||
// constants so errors in the source code can bet detected. It will only (and
|
||||
// must only) be called for initialization purposes.
|
||||
func fromHex(s string) *big.Int { |
||||
if s == "" { |
||||
return big.NewInt(0) |
||||
} |
||||
r, ok := new(big.Int).SetString(s, 16) |
||||
if !ok { |
||||
panic("invalid hex in source file: " + s) |
||||
} |
||||
return r |
||||
} |
||||
|
||||
// jacobianPointFromHex decodes the passed big-endian hex strings into a
|
||||
// Jacobian point with its internal fields set to the resulting values. Only
|
||||
// the first 32-bytes are used.
|
||||
func jacobianPointFromHex(x, y, z string) JacobianPoint { |
||||
var p JacobianPoint |
||||
p.X = *setHex(x) |
||||
p.Y = *setHex(y) |
||||
p.Z = *setHex(z) |
||||
return p |
||||
} |
||||
|
||||
// BenchmarkAddNonConst benchmarks the secp256k1 curve AddNonConst function with
|
||||
// Z values of 1 so that the associated optimizations are used.
|
||||
func BenchmarkAddJacobian(b *testing.B) { |
||||
p1 := jacobianPointFromHex( |
||||
"34f9460f0e4f08393d192b3c5133a6ba099aa0ad9fd54ebccfacdfa239ff49c6", |
||||
"0b71ea9bd730fd8923f6d25a7a91e7dd7728a960686cb5a901bb419e0f2ca232", |
||||
"1", |
||||
) |
||||
p2 := jacobianPointFromHex( |
||||
"34f9460f0e4f08393d192b3c5133a6ba099aa0ad9fd54ebccfacdfa239ff49c6", |
||||
"0b71ea9bd730fd8923f6d25a7a91e7dd7728a960686cb5a901bb419e0f2ca232", |
||||
"1", |
||||
) |
||||
b.ReportAllocs() |
||||
b.ResetTimer() |
||||
var result JacobianPoint |
||||
for i := 0; i < b.N; i++ { |
||||
secp256k1.AddNonConst(&p1, &p2, &result) |
||||
} |
||||
} |
||||
|
||||
// BenchmarkAddNonConstNotZOne benchmarks the secp256k1 curve AddNonConst
|
||||
// function with Z values other than one so the optimizations associated with
|
||||
// Z=1 aren't used.
|
||||
func BenchmarkAddJacobianNotZOne(b *testing.B) { |
||||
x1 := setHex("d3e5183c393c20e4f464acf144ce9ae8266a82b67f553af33eb37e88e7fd2718") |
||||
y1 := setHex("5b8f54deb987ec491fb692d3d48f3eebb9454b034365ad480dda0cf079651190") |
||||
z1 := setHex("2") |
||||
x2 := setHex("91abba6a34b7481d922a4bd6a04899d5a686f6cf6da4e66a0cb427fb25c04bd4") |
||||
y2 := setHex("03fede65e30b4e7576a2abefc963ddbf9fdccbf791b77c29beadefe49951f7d1") |
||||
z2 := setHex("3") |
||||
p1 := MakeJacobianPoint(x1, y1, z1) |
||||
p2 := MakeJacobianPoint(x2, y2, z2) |
||||
b.ReportAllocs() |
||||
b.ResetTimer() |
||||
var result JacobianPoint |
||||
for i := 0; i < b.N; i++ { |
||||
AddNonConst(&p1, &p2, &result) |
||||
} |
||||
} |
||||
|
||||
// BenchmarkScalarBaseMult benchmarks the secp256k1 curve ScalarBaseMult
|
||||
// function.
|
||||
func BenchmarkScalarBaseMult(b *testing.B) { |
||||
k := fromHex("d74bf844b0862475103d96a611cf2d898447e288d34b360bc885cb8ce7c00575") |
||||
curve := S256() |
||||
for i := 0; i < b.N; i++ { |
||||
curve.ScalarBaseMult(k.Bytes()) |
||||
} |
||||
} |
||||
|
||||
// BenchmarkScalarBaseMultLarge benchmarks the secp256k1 curve ScalarBaseMult
|
||||
// function with abnormally large k values.
|
||||
func BenchmarkScalarBaseMultLarge(b *testing.B) { |
||||
k := fromHex("d74bf844b0862475103d96a611cf2d898447e288d34b360bc885cb8ce7c005751111111011111110") |
||||
curve := S256() |
||||
for i := 0; i < b.N; i++ { |
||||
curve.ScalarBaseMult(k.Bytes()) |
||||
} |
||||
} |
||||
|
||||
// BenchmarkScalarMult benchmarks the secp256k1 curve ScalarMult function.
|
||||
func BenchmarkScalarMult(b *testing.B) { |
||||
x := fromHex("34f9460f0e4f08393d192b3c5133a6ba099aa0ad9fd54ebccfacdfa239ff49c6") |
||||
y := fromHex("0b71ea9bd730fd8923f6d25a7a91e7dd7728a960686cb5a901bb419e0f2ca232") |
||||
k := fromHex("d74bf844b0862475103d96a611cf2d898447e288d34b360bc885cb8ce7c00575") |
||||
curve := S256() |
||||
for i := 0; i < b.N; i++ { |
||||
curve.ScalarMult(x, y, k.Bytes()) |
||||
} |
||||
} |
||||
|
||||
// hexToModNScalar converts the passed hex string into a ModNScalar and will
|
||||
// panic if there is an error. This is only provided for the hard-coded
|
||||
// constants so errors in the source code can be detected. It will only (and
|
||||
// must only) be called with hard-coded values.
|
||||
func hexToModNScalar(s string) *ModNScalar { |
||||
b, err := hex.Dec(s) |
||||
if err != nil { |
||||
panic("invalid hex in source file: " + s) |
||||
} |
||||
var scalar ModNScalar |
||||
if overflow := scalar.SetByteSlice(b); overflow { |
||||
panic("hex in source file overflows mod N scalar: " + s) |
||||
} |
||||
return &scalar |
||||
} |
||||
|
||||
// BenchmarkFieldNormalize benchmarks how long it takes the internal field
|
||||
// to perform normalization (which includes modular reduction).
|
||||
func BenchmarkFieldNormalize(b *testing.B) { |
||||
// The normalize function is constant time so default value is fine.
|
||||
var f FieldVal |
||||
for i := 0; i < b.N; i++ { |
||||
f.Normalize() |
||||
} |
||||
} |
||||
|
||||
// BenchmarkParseCompressedPubKey benchmarks how long it takes to decompress and
|
||||
// validate a compressed public key from a byte array.
|
||||
func BenchmarkParseCompressedPubKey(b *testing.B) { |
||||
rawPk, _ := hex.Dec("0234f9460f0e4f08393d192b3c5133a6ba099aa0ad9fd54ebccfacdfa239ff49c6") |
||||
|
||||
var ( |
||||
pk *PublicKey |
||||
err error |
||||
) |
||||
b.ReportAllocs() |
||||
b.ResetTimer() |
||||
for i := 0; i < b.N; i++ { |
||||
pk, err = ParsePubKey(rawPk) |
||||
} |
||||
_ = pk |
||||
_ = err |
||||
} |
||||
@ -1,53 +0,0 @@
@@ -1,53 +0,0 @@
|
||||
// Copyright 2010 The Go Authors. All rights reserved.
|
||||
// Copyright 2011 ThePiachu. All rights reserved.
|
||||
// Copyright 2013-2014 The btcsuite developers
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package btcec |
||||
|
||||
// References:
|
||||
// [SECG]: Recommended Elliptic Curve Domain Parameters
|
||||
// http://www.secg.org/sec2-v2.pdf
|
||||
//
|
||||
// [GECC]: Guide to Elliptic Curve Cryptography (Hankerson, Menezes, Vanstone)
|
||||
|
||||
// This package operates, internally, on Jacobian coordinates. For a given
|
||||
// (x, y) position on the curve, the Jacobian coordinates are (x1, y1, z1)
|
||||
// where x = x1/z1² and y = y1/z1³. The greatest speedups come when the whole
|
||||
// calculation can be performed within the transform (as in ScalarMult and
|
||||
// ScalarBaseMult). But even for Add and Double, it's faster to apply and
|
||||
// reverse the transform than to operate in affine coordinates.
|
||||
|
||||
import ( |
||||
"next.orly.dev/pkg/crypto/ec/secp256k1" |
||||
) |
||||
|
||||
// KoblitzCurve provides an implementation for secp256k1 that fits the ECC
|
||||
// Curve interface from crypto/elliptic.
|
||||
type KoblitzCurve = secp256k1.KoblitzCurve |
||||
|
||||
// S256 returns a Curve which implements secp256k1.
|
||||
func S256() *KoblitzCurve { |
||||
return secp256k1.S256() |
||||
} |
||||
|
||||
// CurveParams contains the parameters for the secp256k1 curve.
|
||||
type CurveParams = secp256k1.CurveParams |
||||
|
||||
// Params returns the secp256k1 curve parameters for convenience.
|
||||
func Params() *CurveParams { |
||||
return secp256k1.Params() |
||||
} |
||||
|
||||
// Generator returns the public key at the Generator Point.
|
||||
func Generator() *PublicKey { |
||||
var ( |
||||
result JacobianPoint |
||||
k secp256k1.ModNScalar |
||||
) |
||||
k.SetInt(1) |
||||
ScalarBaseMultNonConst(&k, &result) |
||||
result.ToAffine() |
||||
return NewPublicKey(&result.X, &result.Y) |
||||
} |
||||
@ -1,918 +0,0 @@
@@ -1,918 +0,0 @@
|
||||
// Copyright 2011 The Go Authors. All rights reserved.
|
||||
// Copyright 2011 ThePiachu. All rights reserved.
|
||||
// Copyright 2013-2016 The btcsuite developers
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package btcec |
||||
|
||||
import ( |
||||
"crypto/rand" |
||||
"fmt" |
||||
"math/big" |
||||
"testing" |
||||
) |
||||
|
||||
// isJacobianOnS256Curve returns boolean if the point (x,y,z) is on the
|
||||
// secp256k1 curve.
|
||||
func isJacobianOnS256Curve(point *JacobianPoint) bool { |
||||
// Elliptic curve equation for secp256k1 is: y^2 = x^3 + 7
|
||||
// In Jacobian coordinates, Y = y/z^3 and X = x/z^2
|
||||
// Thus:
|
||||
// (y/z^3)^2 = (x/z^2)^3 + 7
|
||||
// y^2/z^6 = x^3/z^6 + 7
|
||||
// y^2 = x^3 + 7*z^6
|
||||
var y2, z2, x3, result FieldVal |
||||
y2.SquareVal(&point.Y).Normalize() |
||||
z2.SquareVal(&point.Z) |
||||
x3.SquareVal(&point.X).Mul(&point.X) |
||||
result.SquareVal(&z2).Mul(&z2).MulInt(7).Add(&x3).Normalize() |
||||
return y2.Equals(&result) |
||||
} |
||||
|
||||
// TestAddJacobian tests addition of points projected in Jacobian coordinates.
|
||||
func TestAddJacobian(t *testing.T) { |
||||
tests := []struct { |
||||
x1, y1, z1 string // Coordinates (in hex) of first point to add
|
||||
x2, y2, z2 string // Coordinates (in hex) of second point to add
|
||||
x3, y3, z3 string // Coordinates (in hex) of expected point
|
||||
}{ |
||||
// Addition with a point at infinity (left hand side).
|
||||
// ∞ + P = P
|
||||
{ |
||||
"0", |
||||
"0", |
||||
"0", |
||||
"d74bf844b0862475103d96a611cf2d898447e288d34b360bc885cb8ce7c00575", |
||||
"131c670d414c4546b88ac3ff664611b1c38ceb1c21d76369d7a7a0969d61d97d", |
||||
"1", |
||||
"d74bf844b0862475103d96a611cf2d898447e288d34b360bc885cb8ce7c00575", |
||||
"131c670d414c4546b88ac3ff664611b1c38ceb1c21d76369d7a7a0969d61d97d", |
||||
"1", |
||||
}, |
||||
// Addition with a point at infinity (right hand side).
|
||||
// P + ∞ = P
|
||||
{ |
||||
"d74bf844b0862475103d96a611cf2d898447e288d34b360bc885cb8ce7c00575", |
||||
"131c670d414c4546b88ac3ff664611b1c38ceb1c21d76369d7a7a0969d61d97d", |
||||
"1", |
||||
"0", |
||||
"0", |
||||
"0", |
||||
"d74bf844b0862475103d96a611cf2d898447e288d34b360bc885cb8ce7c00575", |
||||
"131c670d414c4546b88ac3ff664611b1c38ceb1c21d76369d7a7a0969d61d97d", |
||||
"1", |
||||
}, |
||||
// Addition with z1=z2=1 different x values.
|
||||
{ |
||||
"34f9460f0e4f08393d192b3c5133a6ba099aa0ad9fd54ebccfacdfa239ff49c6", |
||||
"0b71ea9bd730fd8923f6d25a7a91e7dd7728a960686cb5a901bb419e0f2ca232", |
||||
"1", |
||||
"d74bf844b0862475103d96a611cf2d898447e288d34b360bc885cb8ce7c00575", |
||||
"131c670d414c4546b88ac3ff664611b1c38ceb1c21d76369d7a7a0969d61d97d", |
||||
"1", |
||||
"0cfbc7da1e569b334460788faae0286e68b3af7379d5504efc25e4dba16e46a6", |
||||
"e205f79361bbe0346b037b4010985dbf4f9e1e955e7d0d14aca876bfa79aad87", |
||||
"44a5646b446e3877a648d6d381370d9ef55a83b666ebce9df1b1d7d65b817b2f", |
||||
}, |
||||
// Addition with z1=z2=1 same x opposite y.
|
||||
// P(x, y, z) + P(x, -y, z) = infinity
|
||||
{ |
||||
"34f9460f0e4f08393d192b3c5133a6ba099aa0ad9fd54ebccfacdfa239ff49c6", |
||||
"0b71ea9bd730fd8923f6d25a7a91e7dd7728a960686cb5a901bb419e0f2ca232", |
||||
"1", |
||||
"34f9460f0e4f08393d192b3c5133a6ba099aa0ad9fd54ebccfacdfa239ff49c6", |
||||
"f48e156428cf0276dc092da5856e182288d7569f97934a56fe44be60f0d359fd", |
||||
"1", |
||||
"0", |
||||
"0", |
||||
"0", |
||||
}, |
||||
// Addition with z1=z2=1 same point.
|
||||
// P(x, y, z) + P(x, y, z) = 2P
|
||||
{ |
||||
"34f9460f0e4f08393d192b3c5133a6ba099aa0ad9fd54ebccfacdfa239ff49c6", |
||||
"0b71ea9bd730fd8923f6d25a7a91e7dd7728a960686cb5a901bb419e0f2ca232", |
||||
"1", |
||||
"34f9460f0e4f08393d192b3c5133a6ba099aa0ad9fd54ebccfacdfa239ff49c6", |
||||
"0b71ea9bd730fd8923f6d25a7a91e7dd7728a960686cb5a901bb419e0f2ca232", |
||||
"1", |
||||
"ec9f153b13ee7bd915882859635ea9730bf0dc7611b2c7b0e37ee64f87c50c27", |
||||
"b082b53702c466dcf6e984a35671756c506c67c2fcb8adb408c44dd0755c8f2a", |
||||
"16e3d537ae61fb1247eda4b4f523cfbaee5152c0d0d96b520376833c1e594464", |
||||
}, |
||||
|
||||
// Addition with z1=z2 (!=1) different x values.
|
||||
{ |
||||
"d3e5183c393c20e4f464acf144ce9ae8266a82b67f553af33eb37e88e7fd2718", |
||||
"5b8f54deb987ec491fb692d3d48f3eebb9454b034365ad480dda0cf079651190", |
||||
"2", |
||||
"5d2fe112c21891d440f65a98473cb626111f8a234d2cd82f22172e369f002147", |
||||
"98e3386a0a622a35c4561ffb32308d8e1c6758e10ebb1b4ebd3d04b4eb0ecbe8", |
||||
"2", |
||||
"cfbc7da1e569b334460788faae0286e68b3af7379d5504efc25e4dba16e46a60", |
||||
"817de4d86ef80d1ac0ded00426176fd3e787a5579f43452b2a1db021e6ac3778", |
||||
"129591ad11b8e1de99235b4e04dc367bd56a0ed99baf3a77c6c75f5a6e05f08d", |
||||
}, |
||||
// Addition with z1=z2 (!=1) same x opposite y.
|
||||
// P(x, y, z) + P(x, -y, z) = infinity
|
||||
{ |
||||
"d3e5183c393c20e4f464acf144ce9ae8266a82b67f553af33eb37e88e7fd2718", |
||||
"5b8f54deb987ec491fb692d3d48f3eebb9454b034365ad480dda0cf079651190", |
||||
"2", |
||||
"d3e5183c393c20e4f464acf144ce9ae8266a82b67f553af33eb37e88e7fd2718", |
||||
"a470ab21467813b6e0496d2c2b70c11446bab4fcbc9a52b7f225f30e869aea9f", |
||||
"2", |
||||
"0", |
||||
"0", |
||||
"0", |
||||
}, |
||||
// Addition with z1=z2 (!=1) same point.
|
||||
// P(x, y, z) + P(x, y, z) = 2P
|
||||
{ |
||||
"d3e5183c393c20e4f464acf144ce9ae8266a82b67f553af33eb37e88e7fd2718", |
||||
"5b8f54deb987ec491fb692d3d48f3eebb9454b034365ad480dda0cf079651190", |
||||
"2", |
||||
"d3e5183c393c20e4f464acf144ce9ae8266a82b67f553af33eb37e88e7fd2718", |
||||
"5b8f54deb987ec491fb692d3d48f3eebb9454b034365ad480dda0cf079651190", |
||||
"2", |
||||
"9f153b13ee7bd915882859635ea9730bf0dc7611b2c7b0e37ee65073c50fabac", |
||||
"2b53702c466dcf6e984a35671756c506c67c2fcb8adb408c44dd125dc91cb988", |
||||
"6e3d537ae61fb1247eda4b4f523cfbaee5152c0d0d96b520376833c2e5944a11", |
||||
}, |
||||
|
||||
// Addition with z1!=z2 and z2=1 different x values.
|
||||
{ |
||||
"d3e5183c393c20e4f464acf144ce9ae8266a82b67f553af33eb37e88e7fd2718", |
||||
"5b8f54deb987ec491fb692d3d48f3eebb9454b034365ad480dda0cf079651190", |
||||
"2", |
||||
"d74bf844b0862475103d96a611cf2d898447e288d34b360bc885cb8ce7c00575", |
||||
"131c670d414c4546b88ac3ff664611b1c38ceb1c21d76369d7a7a0969d61d97d", |
||||
"1", |
||||
"3ef1f68795a6ccd1181e23eab80a1b9a2cebdcde755413bf097936eb5b91b4f3", |
||||
"0bef26c377c068d606f6802130bb7e9f3c3d2abcfa1a295950ed81133561cb04", |
||||
"252b235a2371c3bd3246b69c09b86cf7aad41db3375e74ef8d8ebeb4dc0be11a", |
||||
}, |
||||
// Addition with z1!=z2 and z2=1 same x opposite y.
|
||||
// P(x, y, z) + P(x, -y, z) = infinity
|
||||
{ |
||||
"d3e5183c393c20e4f464acf144ce9ae8266a82b67f553af33eb37e88e7fd2718", |
||||
"5b8f54deb987ec491fb692d3d48f3eebb9454b034365ad480dda0cf079651190", |
||||
"2", |
||||
"34f9460f0e4f08393d192b3c5133a6ba099aa0ad9fd54ebccfacdfa239ff49c6", |
||||
"f48e156428cf0276dc092da5856e182288d7569f97934a56fe44be60f0d359fd", |
||||
"1", |
||||
"0", |
||||
"0", |
||||
"0", |
||||
}, |
||||
// Addition with z1!=z2 and z2=1 same point.
|
||||
// P(x, y, z) + P(x, y, z) = 2P
|
||||
{ |
||||
"d3e5183c393c20e4f464acf144ce9ae8266a82b67f553af33eb37e88e7fd2718", |
||||
"5b8f54deb987ec491fb692d3d48f3eebb9454b034365ad480dda0cf079651190", |
||||
"2", |
||||
"34f9460f0e4f08393d192b3c5133a6ba099aa0ad9fd54ebccfacdfa239ff49c6", |
||||
"0b71ea9bd730fd8923f6d25a7a91e7dd7728a960686cb5a901bb419e0f2ca232", |
||||
"1", |
||||
"9f153b13ee7bd915882859635ea9730bf0dc7611b2c7b0e37ee65073c50fabac", |
||||
"2b53702c466dcf6e984a35671756c506c67c2fcb8adb408c44dd125dc91cb988", |
||||
"6e3d537ae61fb1247eda4b4f523cfbaee5152c0d0d96b520376833c2e5944a11", |
||||
}, |
||||
|
||||
// Addition with z1!=z2 and z2!=1 different x values.
|
||||
// P(x, y, z) + P(x, y, z) = 2P
|
||||
{ |
||||
"d3e5183c393c20e4f464acf144ce9ae8266a82b67f553af33eb37e88e7fd2718", |
||||
"5b8f54deb987ec491fb692d3d48f3eebb9454b034365ad480dda0cf079651190", |
||||
"2", |
||||
"91abba6a34b7481d922a4bd6a04899d5a686f6cf6da4e66a0cb427fb25c04bd4", |
||||
"03fede65e30b4e7576a2abefc963ddbf9fdccbf791b77c29beadefe49951f7d1", |
||||
"3", |
||||
"3f07081927fd3f6dadd4476614c89a09eba7f57c1c6c3b01fa2d64eac1eef31e", |
||||
"949166e04ebc7fd95a9d77e5dfd88d1492ecffd189792e3944eb2b765e09e031", |
||||
"eb8cba81bcffa4f44d75427506737e1f045f21e6d6f65543ee0e1d163540c931", |
||||
}, // Addition with z1!=z2 and z2!=1 same x opposite y.
|
||||
// P(x, y, z) + P(x, -y, z) = infinity
|
||||
{ |
||||
"d3e5183c393c20e4f464acf144ce9ae8266a82b67f553af33eb37e88e7fd2718", |
||||
"5b8f54deb987ec491fb692d3d48f3eebb9454b034365ad480dda0cf079651190", |
||||
"2", |
||||
"dcc3768780c74a0325e2851edad0dc8a566fa61a9e7fc4a34d13dcb509f99bc7", |
||||
"cafc41904dd5428934f7d075129c8ba46eb622d4fc88d72cd1401452664add18", |
||||
"3", |
||||
"0", |
||||
"0", |
||||
"0", |
||||
}, |
||||
// Addition with z1!=z2 and z2!=1 same point.
|
||||
// P(x, y, z) + P(x, y, z) = 2P
|
||||
{ |
||||
"d3e5183c393c20e4f464acf144ce9ae8266a82b67f553af33eb37e88e7fd2718", |
||||
"5b8f54deb987ec491fb692d3d48f3eebb9454b034365ad480dda0cf079651190", |
||||
"2", |
||||
"dcc3768780c74a0325e2851edad0dc8a566fa61a9e7fc4a34d13dcb509f99bc7", |
||||
"3503be6fb22abd76cb082f8aed63745b9149dd2b037728d32ebfebac99b51f17", |
||||
"3", |
||||
"9f153b13ee7bd915882859635ea9730bf0dc7611b2c7b0e37ee65073c50fabac", |
||||
"2b53702c466dcf6e984a35671756c506c67c2fcb8adb408c44dd125dc91cb988", |
||||
"6e3d537ae61fb1247eda4b4f523cfbaee5152c0d0d96b520376833c2e5944a11", |
||||
}, |
||||
} |
||||
|
||||
t.Logf("Running %d tests", len(tests)) |
||||
for i, test := range tests { |
||||
// Convert hex to Jacobian points.
|
||||
p1 := jacobianPointFromHex(test.x1, test.y1, test.z1) |
||||
p2 := jacobianPointFromHex(test.x2, test.y2, test.z2) |
||||
want := jacobianPointFromHex(test.x3, test.y3, test.z3) |
||||
// Ensure the test data is using points that are actually on
|
||||
// the curve (or the point at infinity).
|
||||
if !p1.Z.IsZero() && !isJacobianOnS256Curve(&p1) { |
||||
t.Errorf( |
||||
"#%d first point is not on the curve -- "+ |
||||
"invalid test data", i, |
||||
) |
||||
continue |
||||
} |
||||
if !p2.Z.IsZero() && !isJacobianOnS256Curve(&p2) { |
||||
t.Errorf( |
||||
"#%d second point is not on the curve -- "+ |
||||
"invalid test data", i, |
||||
) |
||||
continue |
||||
} |
||||
if !want.Z.IsZero() && !isJacobianOnS256Curve(&want) { |
||||
t.Errorf( |
||||
"#%d expected point is not on the curve -- "+ |
||||
"invalid test data", i, |
||||
) |
||||
continue |
||||
} |
||||
// Add the two points.
|
||||
var r JacobianPoint |
||||
AddNonConst(&p1, &p2, &r) |
||||
|
||||
// Ensure result matches expected.
|
||||
if !r.X.Equals(&want.X) || !r.Y.Equals(&want.Y) || !r.Z.Equals(&want.Z) { |
||||
t.Errorf( |
||||
"#%d wrong result\ngot: (%v, %v, %v)\n"+ |
||||
"want: (%v, %v, %v)", i, r.X, r.Y, r.Z, want.X, want.Y, |
||||
want.Z, |
||||
) |
||||
continue |
||||
} |
||||
} |
||||
} |
||||
|
||||
// TestAddAffine tests addition of points in affine coordinates.
|
||||
func TestAddAffine(t *testing.T) { |
||||
tests := []struct { |
||||
x1, y1 string // Coordinates (in hex) of first point to add
|
||||
x2, y2 string // Coordinates (in hex) of second point to add
|
||||
x3, y3 string // Coordinates (in hex) of expected point
|
||||
}{ |
||||
// Addition with a point at infinity (left hand side).
|
||||
// ∞ + P = P
|
||||
{ |
||||
"0", |
||||
"0", |
||||
"d74bf844b0862475103d96a611cf2d898447e288d34b360bc885cb8ce7c00575", |
||||
"131c670d414c4546b88ac3ff664611b1c38ceb1c21d76369d7a7a0969d61d97d", |
||||
"d74bf844b0862475103d96a611cf2d898447e288d34b360bc885cb8ce7c00575", |
||||
"131c670d414c4546b88ac3ff664611b1c38ceb1c21d76369d7a7a0969d61d97d", |
||||
}, |
||||
// Addition with a point at infinity (right hand side).
|
||||
// P + ∞ = P
|
||||
{ |
||||
"d74bf844b0862475103d96a611cf2d898447e288d34b360bc885cb8ce7c00575", |
||||
"131c670d414c4546b88ac3ff664611b1c38ceb1c21d76369d7a7a0969d61d97d", |
||||
"0", |
||||
"0", |
||||
"d74bf844b0862475103d96a611cf2d898447e288d34b360bc885cb8ce7c00575", |
||||
"131c670d414c4546b88ac3ff664611b1c38ceb1c21d76369d7a7a0969d61d97d", |
||||
}, |
||||
|
||||
// Addition with different x values.
|
||||
{ |
||||
"34f9460f0e4f08393d192b3c5133a6ba099aa0ad9fd54ebccfacdfa239ff49c6", |
||||
"0b71ea9bd730fd8923f6d25a7a91e7dd7728a960686cb5a901bb419e0f2ca232", |
||||
"d74bf844b0862475103d96a611cf2d898447e288d34b360bc885cb8ce7c00575", |
||||
"131c670d414c4546b88ac3ff664611b1c38ceb1c21d76369d7a7a0969d61d97d", |
||||
"fd5b88c21d3143518d522cd2796f3d726793c88b3e05636bc829448e053fed69", |
||||
"21cf4f6a5be5ff6380234c50424a970b1f7e718f5eb58f68198c108d642a137f", |
||||
}, |
||||
// Addition with same x opposite y.
|
||||
// P(x, y) + P(x, -y) = infinity
|
||||
{ |
||||
"34f9460f0e4f08393d192b3c5133a6ba099aa0ad9fd54ebccfacdfa239ff49c6", |
||||
"0b71ea9bd730fd8923f6d25a7a91e7dd7728a960686cb5a901bb419e0f2ca232", |
||||
"34f9460f0e4f08393d192b3c5133a6ba099aa0ad9fd54ebccfacdfa239ff49c6", |
||||
"f48e156428cf0276dc092da5856e182288d7569f97934a56fe44be60f0d359fd", |
||||
"0", |
||||
"0", |
||||
}, |
||||
// Addition with same point.
|
||||
// P(x, y) + P(x, y) = 2P
|
||||
{ |
||||
"34f9460f0e4f08393d192b3c5133a6ba099aa0ad9fd54ebccfacdfa239ff49c6", |
||||
"0b71ea9bd730fd8923f6d25a7a91e7dd7728a960686cb5a901bb419e0f2ca232", |
||||
"34f9460f0e4f08393d192b3c5133a6ba099aa0ad9fd54ebccfacdfa239ff49c6", |
||||
"0b71ea9bd730fd8923f6d25a7a91e7dd7728a960686cb5a901bb419e0f2ca232", |
||||
"59477d88ae64a104dbb8d31ec4ce2d91b2fe50fa628fb6a064e22582196b365b", |
||||
"938dc8c0f13d1e75c987cb1a220501bd614b0d3dd9eb5c639847e1240216e3b6", |
||||
}, |
||||
} |
||||
t.Logf("Running %d tests", len(tests)) |
||||
for i, test := range tests { |
||||
// Convert hex to field values.
|
||||
x1, y1 := fromHex(test.x1), fromHex(test.y1) |
||||
x2, y2 := fromHex(test.x2), fromHex(test.y2) |
||||
x3, y3 := fromHex(test.x3), fromHex(test.y3) |
||||
// Ensure the test data is using points that are actually on
|
||||
// the curve (or the point at infinity).
|
||||
if !(x1.Sign() == 0 && y1.Sign() == 0) && !S256().IsOnCurve(x1, y1) { |
||||
t.Errorf( |
||||
"#%d first point is not on the curve -- "+ |
||||
"invalid test data", i, |
||||
) |
||||
continue |
||||
} |
||||
if !(x2.Sign() == 0 && y2.Sign() == 0) && !S256().IsOnCurve(x2, y2) { |
||||
t.Errorf( |
||||
"#%d second point is not on the curve -- "+ |
||||
"invalid test data", i, |
||||
) |
||||
continue |
||||
} |
||||
if !(x3.Sign() == 0 && y3.Sign() == 0) && !S256().IsOnCurve(x3, y3) { |
||||
t.Errorf( |
||||
"#%d expected point is not on the curve -- "+ |
||||
"invalid test data", i, |
||||
) |
||||
continue |
||||
} |
||||
// Add the two points.
|
||||
rx, ry := S256().Add(x1, y1, x2, y2) |
||||
|
||||
// Ensure result matches expected.
|
||||
if rx.Cmp(x3) != 00 || ry.Cmp(y3) != 0 { |
||||
t.Errorf( |
||||
"#%d wrong result\ngot: (%x, %x)\n"+ |
||||
"want: (%x, %x)", i, rx, ry, x3, y3, |
||||
) |
||||
continue |
||||
} |
||||
} |
||||
} |
||||
|
||||
// isStrictlyEqual returns whether or not the two Jacobian points are strictly
|
||||
// equal for use in the tests. Recall that several Jacobian points can be
|
||||
// equal in affine coordinates, while not having the same coordinates in
|
||||
// projective space, so the two points not being equal doesn't necessarily mean
|
||||
// they aren't actually the same affine point.
|
||||
func isStrictlyEqual(p, other *JacobianPoint) bool { |
||||
return p.X.Equals(&other.X) && p.Y.Equals(&other.Y) && p.Z.Equals(&other.Z) |
||||
} |
||||
|
||||
// TestDoubleJacobian tests doubling of points projected in Jacobian
|
||||
// coordinates.
|
||||
func TestDoubleJacobian(t *testing.T) { |
||||
tests := []struct { |
||||
x1, y1, z1 string // Coordinates (in hex) of point to double
|
||||
x3, y3, z3 string // Coordinates (in hex) of expected point
|
||||
}{ |
||||
// Doubling a point at infinity is still infinity.
|
||||
{ |
||||
"0", |
||||
"0", |
||||
"0", |
||||
"0", |
||||
"0", |
||||
"0", |
||||
}, |
||||
// Doubling with z1=1.
|
||||
{ |
||||
"34f9460f0e4f08393d192b3c5133a6ba099aa0ad9fd54ebccfacdfa239ff49c6", |
||||
"0b71ea9bd730fd8923f6d25a7a91e7dd7728a960686cb5a901bb419e0f2ca232", |
||||
"1", |
||||
"ec9f153b13ee7bd915882859635ea9730bf0dc7611b2c7b0e37ee64f87c50c27", |
||||
"b082b53702c466dcf6e984a35671756c506c67c2fcb8adb408c44dd0755c8f2a", |
||||
"16e3d537ae61fb1247eda4b4f523cfbaee5152c0d0d96b520376833c1e594464", |
||||
}, |
||||
// Doubling with z1!=1.
|
||||
{ |
||||
"d3e5183c393c20e4f464acf144ce9ae8266a82b67f553af33eb37e88e7fd2718", |
||||
"5b8f54deb987ec491fb692d3d48f3eebb9454b034365ad480dda0cf079651190", |
||||
"2", |
||||
"9f153b13ee7bd915882859635ea9730bf0dc7611b2c7b0e37ee65073c50fabac", |
||||
"2b53702c466dcf6e984a35671756c506c67c2fcb8adb408c44dd125dc91cb988", |
||||
"6e3d537ae61fb1247eda4b4f523cfbaee5152c0d0d96b520376833c2e5944a11", |
||||
}, |
||||
// From btcd issue #709.
|
||||
{ |
||||
"201e3f75715136d2f93c4f4598f91826f94ca01f4233a5bd35de9708859ca50d", |
||||
"bdf18566445e7562c6ada68aef02d498d7301503de5b18c6aef6e2b1722412e1", |
||||
"0000000000000000000000000000000000000000000000000000000000000001", |
||||
"4a5e0559863ebb4e9ed85f5c4fa76003d05d9a7626616e614a1f738621e3c220", |
||||
"00000000000000000000000000000000000000000000000000000001b1388778", |
||||
"7be30acc88bceac58d5b4d15de05a931ae602a07bcb6318d5dedc563e4482993", |
||||
}, |
||||
} |
||||
t.Logf("Running %d tests", len(tests)) |
||||
for i, test := range tests { |
||||
// Convert hex to field values.
|
||||
p1 := jacobianPointFromHex(test.x1, test.y1, test.z1) |
||||
want := jacobianPointFromHex(test.x3, test.y3, test.z3) |
||||
// Ensure the test data is using points that are actually on
|
||||
// the curve (or the point at infinity).
|
||||
if !p1.Z.IsZero() && !isJacobianOnS256Curve(&p1) { |
||||
t.Errorf( |
||||
"#%d first point is not on the curve -- "+ |
||||
"invalid test data", i, |
||||
) |
||||
continue |
||||
} |
||||
if !want.Z.IsZero() && !isJacobianOnS256Curve(&want) { |
||||
t.Errorf( |
||||
"#%d expected point is not on the curve -- "+ |
||||
"invalid test data", i, |
||||
) |
||||
continue |
||||
} |
||||
// Double the point.
|
||||
var result JacobianPoint |
||||
DoubleNonConst(&p1, &result) |
||||
// Ensure result matches expected.
|
||||
if !isStrictlyEqual(&result, &want) { |
||||
t.Errorf( |
||||
"#%d wrong result\ngot: (%v, %v, %v)\n"+ |
||||
"want: (%v, %v, %v)", i, result.X, result.Y, result.Z, |
||||
want.X, want.Y, want.Z, |
||||
) |
||||
continue |
||||
} |
||||
} |
||||
} |
||||
|
||||
// TestDoubleAffine tests doubling of points in affine coordinates.
|
||||
func TestDoubleAffine(t *testing.T) { |
||||
tests := []struct { |
||||
x1, y1 string // Coordinates (in hex) of point to double
|
||||
x3, y3 string // Coordinates (in hex) of expected point
|
||||
}{ |
||||
// Doubling a point at infinity is still infinity.
|
||||
// 2*∞ = ∞ (point at infinity)
|
||||
{ |
||||
"0", |
||||
"0", |
||||
"0", |
||||
"0", |
||||
}, |
||||
// Random points.
|
||||
{ |
||||
"e41387ffd8baaeeb43c2faa44e141b19790e8ac1f7ff43d480dc132230536f86", |
||||
"1b88191d430f559896149c86cbcb703193105e3cf3213c0c3556399836a2b899", |
||||
"88da47a089d333371bd798c548ef7caae76e737c1980b452d367b3cfe3082c19", |
||||
"3b6f659b09a362821dfcfefdbfbc2e59b935ba081b6c249eb147b3c2100b1bc1", |
||||
}, |
||||
{ |
||||
"b3589b5d984f03ef7c80aeae444f919374799edf18d375cab10489a3009cff0c", |
||||
"c26cf343875b3630e15bccc61202815b5d8f1fd11308934a584a5babe69db36a", |
||||
"e193860172998751e527bb12563855602a227fc1f612523394da53b746bb2fb1", |
||||
"2bfcf13d2f5ab8bb5c611fab5ebbed3dc2f057062b39a335224c22f090c04789", |
||||
}, |
||||
{ |
||||
"2b31a40fbebe3440d43ac28dba23eee71c62762c3fe3dbd88b4ab82dc6a82340", |
||||
"9ba7deb02f5c010e217607fd49d58db78ec273371ea828b49891ce2fd74959a1", |
||||
"2c8d5ef0d343b1a1a48aa336078eadda8481cb048d9305dc4fdf7ee5f65973a2", |
||||
"bb4914ac729e26d3cd8f8dc8f702f3f4bb7e0e9c5ae43335f6e94c2de6c3dc95", |
||||
}, |
||||
{ |
||||
"61c64b760b51981fab54716d5078ab7dffc93730b1d1823477e27c51f6904c7a", |
||||
"ef6eb16ea1a36af69d7f66524c75a3a5e84c13be8fbc2e811e0563c5405e49bd", |
||||
"5f0dcdd2595f5ad83318a0f9da481039e36f135005420393e72dfca985b482f4", |
||||
"a01c849b0837065c1cb481b0932c441f49d1cab1b4b9f355c35173d93f110ae0", |
||||
}, |
||||
} |
||||
|
||||
t.Logf("Running %d tests", len(tests)) |
||||
for i, test := range tests { |
||||
// Convert hex to field values.
|
||||
x1, y1 := fromHex(test.x1), fromHex(test.y1) |
||||
x3, y3 := fromHex(test.x3), fromHex(test.y3) |
||||
// Ensure the test data is using points that are actually on
|
||||
// the curve (or the point at infinity).
|
||||
if !(x1.Sign() == 0 && y1.Sign() == 0) && !S256().IsOnCurve(x1, y1) { |
||||
t.Errorf( |
||||
"#%d first point is not on the curve -- "+ |
||||
"invalid test data", i, |
||||
) |
||||
continue |
||||
} |
||||
if !(x3.Sign() == 0 && y3.Sign() == 0) && !S256().IsOnCurve(x3, y3) { |
||||
t.Errorf( |
||||
"#%d expected point is not on the curve -- "+ |
||||
"invalid test data", i, |
||||
) |
||||
continue |
||||
} |
||||
// Double the point.
|
||||
rx, ry := S256().Double(x1, y1) |
||||
|
||||
// Ensure result matches expected.
|
||||
if rx.Cmp(x3) != 00 || ry.Cmp(y3) != 0 { |
||||
t.Errorf( |
||||
"#%d wrong result\ngot: (%x, %x)\n"+ |
||||
"want: (%x, %x)", i, rx, ry, x3, y3, |
||||
) |
||||
continue |
||||
} |
||||
} |
||||
} |
||||
|
||||
func TestOnCurve(t *testing.T) { |
||||
s256 := S256() |
||||
if !s256.IsOnCurve(s256.Params().Gx, s256.Params().Gy) { |
||||
t.Errorf("FAIL S256") |
||||
} |
||||
} |
||||
|
||||
type baseMultTest struct { |
||||
k string |
||||
x, y string |
||||
} |
||||
|
||||
// TODO: add more test vectors
|
||||
var s256BaseMultTests = []baseMultTest{ |
||||
{ |
||||
"AA5E28D6A97A2479A65527F7290311A3624D4CC0FA1578598EE3C2613BF99522", |
||||
"34F9460F0E4F08393D192B3C5133A6BA099AA0AD9FD54EBCCFACDFA239FF49C6", |
||||
"B71EA9BD730FD8923F6D25A7A91E7DD7728A960686CB5A901BB419E0F2CA232", |
||||
}, |
||||
{ |
||||
"7E2B897B8CEBC6361663AD410835639826D590F393D90A9538881735256DFAE3", |
||||
"D74BF844B0862475103D96A611CF2D898447E288D34B360BC885CB8CE7C00575", |
||||
"131C670D414C4546B88AC3FF664611B1C38CEB1C21D76369D7A7A0969D61D97D", |
||||
}, |
||||
{ |
||||
"6461E6DF0FE7DFD05329F41BF771B86578143D4DD1F7866FB4CA7E97C5FA945D", |
||||
"E8AECC370AEDD953483719A116711963CE201AC3EB21D3F3257BB48668C6A72F", |
||||
"C25CAF2F0EBA1DDB2F0F3F47866299EF907867B7D27E95B3873BF98397B24EE1", |
||||
}, |
||||
{ |
||||
"376A3A2CDCD12581EFFF13EE4AD44C4044B8A0524C42422A7E1E181E4DEECCEC", |
||||
"14890E61FCD4B0BD92E5B36C81372CA6FED471EF3AA60A3E415EE4FE987DABA1", |
||||
"297B858D9F752AB42D3BCA67EE0EB6DCD1C2B7B0DBE23397E66ADC272263F982", |
||||
}, |
||||
{ |
||||
"1B22644A7BE026548810C378D0B2994EEFA6D2B9881803CB02CEFF865287D1B9", |
||||
"F73C65EAD01C5126F28F442D087689BFA08E12763E0CEC1D35B01751FD735ED3", |
||||
"F449A8376906482A84ED01479BD18882B919C140D638307F0C0934BA12590BDE", |
||||
}, |
||||
} |
||||
|
||||
// TODO: test different curves as well?
|
||||
func TestBaseMult(t *testing.T) { |
||||
s256 := S256() |
||||
for i, e := range s256BaseMultTests { |
||||
k, ok := new(big.Int).SetString(e.k, 16) |
||||
if !ok { |
||||
t.Errorf("%d: bad value for k: %s", i, e.k) |
||||
} |
||||
x, y := s256.ScalarBaseMult(k.Bytes()) |
||||
if fmt.Sprintf("%X", x) != e.x || fmt.Sprintf("%X", y) != e.y { |
||||
t.Errorf( |
||||
"%d: bad output for k=%s: got (%X, %X), want (%s, %s)", i, |
||||
e.k, x, y, e.x, e.y, |
||||
) |
||||
} |
||||
if testing.Short() && i > 5 { |
||||
break |
||||
} |
||||
} |
||||
} |
||||
|
||||
func TestBaseMultVerify(t *testing.T) { |
||||
s256 := S256() |
||||
for bytes := 1; bytes < 40; bytes++ { |
||||
for i := 0; i < 30; i++ { |
||||
data := make([]byte, bytes) |
||||
_, err := rand.Read(data) |
||||
if err != nil { |
||||
t.Errorf("failed to read random data for %d", i) |
||||
continue |
||||
} |
||||
x, y := s256.ScalarBaseMult(data) |
||||
xWant, yWant := s256.ScalarMult(s256.Gx, s256.Gy, data) |
||||
if x.Cmp(xWant) != 0 || y.Cmp(yWant) != 0 { |
||||
t.Errorf( |
||||
"%d: bad output for %X: got (%X, %X), want (%X, %X)", |
||||
i, data, x, y, xWant, yWant, |
||||
) |
||||
} |
||||
if testing.Short() && i > 2 { |
||||
break |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
func TestScalarMult(t *testing.T) { |
||||
tests := []struct { |
||||
x string |
||||
y string |
||||
k string |
||||
rx string |
||||
ry string |
||||
}{ |
||||
// base mult, essentially.
|
||||
{ |
||||
"79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798", |
||||
"483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8", |
||||
"18e14a7b6a307f426a94f8114701e7c8e774e7f9a47e2c2035db29a206321725", |
||||
"50863ad64a87ae8a2fe83c1af1a8403cb53f53e486d8511dad8a04887e5b2352", |
||||
"2cd470243453a299fa9e77237716103abc11a1df38855ed6f2ee187e9c582ba6", |
||||
}, |
||||
// From btcd issue #709.
|
||||
{ |
||||
"000000000000000000000000000000000000000000000000000000000000002c", |
||||
"420e7a99bba18a9d3952597510fd2b6728cfeafc21a4e73951091d4d8ddbe94e", |
||||
"a2e8ba2e8ba2e8ba2e8ba2e8ba2e8ba219b51835b55cc30ebfe2f6599bc56f58", |
||||
"a2112dcdfbcd10ae1133a358de7b82db68e0a3eb4b492cc8268d1e7118c98788", |
||||
"27fc7463b7bb3c5f98ecf2c84a6272bb1681ed553d92c69f2dfe25a9f9fd3836", |
||||
}, |
||||
} |
||||
s256 := S256() |
||||
for i, test := range tests { |
||||
x, _ := new(big.Int).SetString(test.x, 16) |
||||
y, _ := new(big.Int).SetString(test.y, 16) |
||||
k, _ := new(big.Int).SetString(test.k, 16) |
||||
xWant, _ := new(big.Int).SetString(test.rx, 16) |
||||
yWant, _ := new(big.Int).SetString(test.ry, 16) |
||||
xGot, yGot := s256.ScalarMult(x, y, k.Bytes()) |
||||
if xGot.Cmp(xWant) != 0 || yGot.Cmp(yWant) != 0 { |
||||
t.Fatalf( |
||||
"%d: bad output: got (%X, %X), want (%X, %X)", i, xGot, |
||||
yGot, xWant, yWant, |
||||
) |
||||
} |
||||
} |
||||
} |
||||
|
||||
func TestScalarMultRand(t *testing.T) { |
||||
// Strategy for this test:
|
||||
// Get a random exponent from the generator point at first
|
||||
// This creates a new point which is used in the next iteration
|
||||
// Use another random exponent on the new point.
|
||||
// We use BaseMult to verify by multiplying the previous exponent
|
||||
// and the new random exponent together (mod no)
|
||||
s256 := S256() |
||||
x, y := s256.Gx, s256.Gy |
||||
exponent := big.NewInt(1) |
||||
for i := 0; i < 1024; i++ { |
||||
data := make([]byte, 32) |
||||
_, err := rand.Read(data) |
||||
if err != nil { |
||||
t.Fatalf("failed to read random data at %d", i) |
||||
break |
||||
} |
||||
x, y = s256.ScalarMult(x, y, data) |
||||
exponent.Mul(exponent, new(big.Int).SetBytes(data)) |
||||
xWant, yWant := s256.ScalarBaseMult(exponent.Bytes()) |
||||
if x.Cmp(xWant) != 0 || y.Cmp(yWant) != 0 { |
||||
t.Fatalf( |
||||
"%d: bad output for %X: got (%X, %X), want (%X, %X)", i, |
||||
data, x, y, xWant, yWant, |
||||
) |
||||
break |
||||
} |
||||
} |
||||
} |
||||
|
||||
var ( |
||||
// Next 6 constants are from Hal Finney's bitcointalk.org post:
|
||||
// https://bitcointalk.org/index.php?topic=3238.msg45565#msg45565
|
||||
// May he rest in peace.
|
||||
//
|
||||
// They have also been independently derived from the code in the
|
||||
// EndomorphismVectors function in genstatics.go.
|
||||
endomorphismLambda = fromHex("5363ad4cc05c30e0a5261c028812645a122e22ea20816678df02967c1b23bd72") |
||||
endomorphismBeta = hexToFieldVal("7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501ee") |
||||
endomorphismA1 = fromHex("3086d221a7d46bcde86c90e49284eb15") |
||||
endomorphismB1 = fromHex("-e4437ed6010e88286f547fa90abfe4c3") |
||||
endomorphismA2 = fromHex("114ca50f7a8e2f3f657c1108d9d44cfd8") |
||||
endomorphismB2 = fromHex("3086d221a7d46bcde86c90e49284eb15") |
||||
) |
||||
|
||||
// splitK returns a balanced length-two representation of k and their signs.
|
||||
// This is algorithm 3.74 from [GECC].
|
||||
//
|
||||
// One thing of note about this algorithm is that no matter what c1 and c2 are,
|
||||
// the final equation of k = k1 + k2 * lambda (mod n) will hold. This is
|
||||
// provable mathematically due to how a1/b1/a2/b2 are computed.
|
||||
//
|
||||
// c1 and c2 are chosen to minimize the max(k1,k2).
|
||||
func splitK(k []byte) ([]byte, []byte, int, int) { |
||||
// All math here is done with big.Int, which is slow.
|
||||
// At some point, it might be useful to write something similar to
|
||||
// FieldVal but for no instead of P as the prime field if this ends up
|
||||
// being a bottleneck.
|
||||
bigIntK := new(big.Int) |
||||
c1, c2 := new(big.Int), new(big.Int) |
||||
tmp1, tmp2 := new(big.Int), new(big.Int) |
||||
k1, k2 := new(big.Int), new(big.Int) |
||||
bigIntK.SetBytes(k) |
||||
// c1 = round(b2 * k / n) from step 4.
|
||||
// Rounding isn't really necessary and costs too much, hence skipped
|
||||
c1.Mul(endomorphismB2, bigIntK) |
||||
c1.Div(c1, Params().N) |
||||
// c2 = round(b1 * k / n) from step 4 (sign reversed to optimize one step)
|
||||
// Rounding isn't really necessary and costs too much, hence skipped
|
||||
c2.Mul(endomorphismB1, bigIntK) |
||||
c2.Div(c2, Params().N) |
||||
// k1 = k - c1 * a1 - c2 * a2 from step 5 (note c2's sign is reversed)
|
||||
tmp1.Mul(c1, endomorphismA1) |
||||
tmp2.Mul(c2, endomorphismA2) |
||||
k1.Sub(bigIntK, tmp1) |
||||
k1.Add(k1, tmp2) |
||||
// k2 = - c1 * b1 - c2 * b2 from step 5 (note c2's sign is reversed)
|
||||
tmp1.Mul(c1, endomorphismB1) |
||||
tmp2.Mul(c2, endomorphismB2) |
||||
k2.Sub(tmp2, tmp1) |
||||
// Note Bytes() throws out the sign of k1 and k2. This matters
|
||||
// since k1 and/or k2 can be negative. Hence, we pass that
|
||||
// back separately.
|
||||
return k1.Bytes(), k2.Bytes(), k1.Sign(), k2.Sign() |
||||
} |
||||
|
||||
func TestSplitK(t *testing.T) { |
||||
tests := []struct { |
||||
k string |
||||
k1, k2 string |
||||
s1, s2 int |
||||
}{ |
||||
{ |
||||
"6df2b5d30854069ccdec40ae022f5c948936324a4e9ebed8eb82cfd5a6b6d766", |
||||
"00000000000000000000000000000000b776e53fb55f6b006a270d42d64ec2b1", |
||||
"00000000000000000000000000000000d6cc32c857f1174b604eefc544f0c7f7", |
||||
-1, -1, |
||||
}, |
||||
{ |
||||
"6ca00a8f10632170accc1b3baf2a118fa5725f41473f8959f34b8f860c47d88d", |
||||
"0000000000000000000000000000000007b21976c1795723c1bfbfa511e95b84", |
||||
"00000000000000000000000000000000d8d2d5f9d20fc64fd2cf9bda09a5bf90", |
||||
1, -1, |
||||
}, |
||||
{ |
||||
"b2eda8ab31b259032d39cbc2a234af17fcee89c863a8917b2740b67568166289", |
||||
"00000000000000000000000000000000507d930fecda7414fc4a523b95ef3c8c", |
||||
"00000000000000000000000000000000f65ffb179df189675338c6185cb839be", |
||||
-1, -1, |
||||
}, |
||||
{ |
||||
"f6f00e44f179936f2befc7442721b0633f6bafdf7161c167ffc6f7751980e3a0", |
||||
"0000000000000000000000000000000008d0264f10bcdcd97da3faa38f85308d", |
||||
"0000000000000000000000000000000065fed1506eb6605a899a54e155665f79", |
||||
-1, -1, |
||||
}, |
||||
{ |
||||
"8679085ab081dc92cdd23091ce3ee998f6b320e419c3475fae6b5b7d3081996e", |
||||
"0000000000000000000000000000000089fbf24fbaa5c3c137b4f1cedc51d975", |
||||
"00000000000000000000000000000000d38aa615bd6754d6f4d51ccdaf529fea", |
||||
-1, -1, |
||||
}, |
||||
{ |
||||
"6b1247bb7931dfcae5b5603c8b5ae22ce94d670138c51872225beae6bba8cdb3", |
||||
"000000000000000000000000000000008acc2a521b21b17cfb002c83be62f55d", |
||||
"0000000000000000000000000000000035f0eff4d7430950ecb2d94193dedc79", |
||||
-1, -1, |
||||
}, |
||||
{ |
||||
"a2e8ba2e8ba2e8ba2e8ba2e8ba2e8ba219b51835b55cc30ebfe2f6599bc56f58", |
||||
"0000000000000000000000000000000045c53aa1bb56fcd68c011e2dad6758e4", |
||||
"00000000000000000000000000000000a2e79d200f27f2360fba57619936159b", |
||||
-1, -1, |
||||
}, |
||||
} |
||||
s256 := S256() |
||||
for i, test := range tests { |
||||
k, ok := new(big.Int).SetString(test.k, 16) |
||||
if !ok { |
||||
t.Errorf("%d: bad value for k: %s", i, test.k) |
||||
} |
||||
k1, k2, k1Sign, k2Sign := splitK(k.Bytes()) |
||||
k1str := fmt.Sprintf("%064x", k1) |
||||
if test.k1 != k1str { |
||||
t.Errorf("%d: bad k1: got %v, want %v", i, k1str, test.k1) |
||||
} |
||||
k2str := fmt.Sprintf("%064x", k2) |
||||
if test.k2 != k2str { |
||||
t.Errorf("%d: bad k2: got %v, want %v", i, k2str, test.k2) |
||||
} |
||||
if test.s1 != k1Sign { |
||||
t.Errorf("%d: bad k1 sign: got %d, want %d", i, k1Sign, test.s1) |
||||
} |
||||
if test.s2 != k2Sign { |
||||
t.Errorf("%d: bad k2 sign: got %d, want %d", i, k2Sign, test.s2) |
||||
} |
||||
k1Int := new(big.Int).SetBytes(k1) |
||||
k1SignInt := new(big.Int).SetInt64(int64(k1Sign)) |
||||
k1Int.Mul(k1Int, k1SignInt) |
||||
k2Int := new(big.Int).SetBytes(k2) |
||||
k2SignInt := new(big.Int).SetInt64(int64(k2Sign)) |
||||
k2Int.Mul(k2Int, k2SignInt) |
||||
gotK := new(big.Int).Mul(k2Int, endomorphismLambda) |
||||
gotK.Add(k1Int, gotK) |
||||
gotK.Mod(gotK, s256.N) |
||||
if k.Cmp(gotK) != 0 { |
||||
t.Errorf("%d: bad k: got %X, want %X", i, gotK.Bytes(), k.Bytes()) |
||||
} |
||||
} |
||||
} |
||||
|
||||
func TestSplitKRand(t *testing.T) { |
||||
s256 := S256() |
||||
for i := 0; i < 1024; i++ { |
||||
bytesK := make([]byte, 32) |
||||
_, err := rand.Read(bytesK) |
||||
if err != nil { |
||||
t.Fatalf("failed to read random data at %d", i) |
||||
break |
||||
} |
||||
k := new(big.Int).SetBytes(bytesK) |
||||
k1, k2, k1Sign, k2Sign := splitK(bytesK) |
||||
k1Int := new(big.Int).SetBytes(k1) |
||||
k1SignInt := new(big.Int).SetInt64(int64(k1Sign)) |
||||
k1Int.Mul(k1Int, k1SignInt) |
||||
k2Int := new(big.Int).SetBytes(k2) |
||||
k2SignInt := new(big.Int).SetInt64(int64(k2Sign)) |
||||
k2Int.Mul(k2Int, k2SignInt) |
||||
gotK := new(big.Int).Mul(k2Int, endomorphismLambda) |
||||
gotK.Add(k1Int, gotK) |
||||
gotK.Mod(gotK, s256.N) |
||||
if k.Cmp(gotK) != 0 { |
||||
t.Errorf("%d: bad k: got %X, want %X", i, gotK.Bytes(), k.Bytes()) |
||||
} |
||||
} |
||||
} |
||||
|
||||
// Test this curve's usage with the ecdsa package.
|
||||
|
||||
func testKeyGeneration(t *testing.T, c *KoblitzCurve, tag string) { |
||||
priv, err := NewSecretKey() |
||||
if err != nil { |
||||
t.Errorf("%s: error: %s", tag, err) |
||||
return |
||||
} |
||||
pub := priv.PubKey() |
||||
if !c.IsOnCurve(pub.X(), pub.Y()) { |
||||
t.Errorf("%s: public key invalid: %s", tag, err) |
||||
} |
||||
} |
||||
|
||||
func TestKeyGeneration(t *testing.T) { |
||||
testKeyGeneration(t, S256(), "S256") |
||||
} |
||||
|
||||
// checkNAFEncoding returns an error if the provided positive and negative
|
||||
// portions of an overall NAF encoding do not adhere to the requirements or they
|
||||
// do not sum back to the provided original value.
|
||||
func checkNAFEncoding(pos, neg []byte, origValue *big.Int) error { |
||||
// NAF must not have a leading zero byte and the number of negative
|
||||
// bytes must not exceed the positive portion.
|
||||
if len(pos) > 0 && pos[0] == 0 { |
||||
return fmt.Errorf("positive has leading zero -- got %x", pos) |
||||
} |
||||
if len(neg) > len(pos) { |
||||
return fmt.Errorf( |
||||
"negative has len %d > pos len %d", len(neg), |
||||
len(pos), |
||||
) |
||||
} |
||||
// Ensure the result doesn't have any adjacent non-zero digits.
|
||||
gotPos := new(big.Int).SetBytes(pos) |
||||
gotNeg := new(big.Int).SetBytes(neg) |
||||
posOrNeg := new(big.Int).Or(gotPos, gotNeg) |
||||
prevBit := posOrNeg.Bit(0) |
||||
for bit := 1; bit < posOrNeg.BitLen(); bit++ { |
||||
thisBit := posOrNeg.Bit(bit) |
||||
if prevBit == 1 && thisBit == 1 { |
||||
return fmt.Errorf( |
||||
"adjacent non-zero digits found at bit pos %d", |
||||
bit-1, |
||||
) |
||||
} |
||||
prevBit = thisBit |
||||
} |
||||
// Ensure the resulting positive and negative portions of the overall
|
||||
// NAF representation sum back to the original value.
|
||||
gotValue := new(big.Int).Sub(gotPos, gotNeg) |
||||
if origValue.Cmp(gotValue) != 0 { |
||||
return fmt.Errorf( |
||||
"pos-neg is not original value: got %x, want %x", |
||||
gotValue, origValue, |
||||
) |
||||
} |
||||
return nil |
||||
} |
||||
@ -1,153 +0,0 @@
@@ -1,153 +0,0 @@
|
||||
package chaincfg |
||||
|
||||
import ( |
||||
"fmt" |
||||
"time" |
||||
|
||||
"next.orly.dev/pkg/crypto/ec/wire" |
||||
) |
||||
|
||||
var ( |
||||
// ErrNoBlockClock is returned when an operation fails due to lack of
|
||||
// synchornization with the current up to date block clock.
|
||||
ErrNoBlockClock = fmt.Errorf("no block clock synchronized") |
||||
) |
||||
|
||||
// ConsensusDeploymentStarter determines if a given consensus deployment has
|
||||
// started. A deployment has started once according to the current "time", the
|
||||
// deployment is eligible for activation once a perquisite condition has
|
||||
// passed.
|
||||
type ConsensusDeploymentStarter interface { |
||||
// HasStarted returns true if the consensus deployment has started.
|
||||
HasStarted(*wire.BlockHeader) (bool, error) |
||||
} |
||||
|
||||
// ConsensusDeploymentEnder determines if a given consensus deployment has
|
||||
// ended. A deployment has ended once according got eh current "time", the
|
||||
// deployment is no longer eligible for activation.
|
||||
type ConsensusDeploymentEnder interface { |
||||
// HasEnded returns true if the consensus deployment has ended.
|
||||
HasEnded(*wire.BlockHeader) (bool, error) |
||||
} |
||||
|
||||
// BlockClock is an abstraction over the past median time computation. The past
|
||||
// median time computation is used in several consensus checks such as CSV, and
|
||||
// also BIP 9 version bits. This interface allows callers to abstract away the
|
||||
// computation of the past median time from the perspective of a given block
|
||||
// header.
|
||||
type BlockClock interface { |
||||
// PastMedianTime returns the past median time from the PoV of the
|
||||
// passed block header. The past median time is the median time of the
|
||||
// 11 blocks prior to the passed block header.
|
||||
PastMedianTime(*wire.BlockHeader) (time.Time, error) |
||||
} |
||||
|
||||
// ClockConsensusDeploymentEnder is a more specialized version of the
|
||||
// ConsensusDeploymentEnder that uses a BlockClock in order to determine if a
|
||||
// deployment has started or not.
|
||||
//
|
||||
// NOTE: Any calls to HasEnded will _fail_ with ErrNoBlockClock if they
|
||||
// happen before SynchronizeClock is executed.
|
||||
type ClockConsensusDeploymentEnder interface { |
||||
ConsensusDeploymentEnder |
||||
// SynchronizeClock synchronizes the target ConsensusDeploymentStarter
|
||||
// with the current up-to date BlockClock.
|
||||
SynchronizeClock(clock BlockClock) |
||||
} |
||||
|
||||
// MedianTimeDeploymentStarter is a ClockConsensusDeploymentStarter that uses
|
||||
// the median time past of a target block node to determine if a deployment has
|
||||
// started.
|
||||
type MedianTimeDeploymentStarter struct { |
||||
blockClock BlockClock |
||||
startTime time.Time |
||||
} |
||||
|
||||
// NewMedianTimeDeploymentStarter returns a new instance of a
|
||||
// MedianTimeDeploymentStarter for a given start time. Using a time.Time
|
||||
// instance where IsZero() is true, indicates that a deployment should be
|
||||
// considered to always have been started.
|
||||
func NewMedianTimeDeploymentStarter(startTime time.Time) *MedianTimeDeploymentStarter { |
||||
return &MedianTimeDeploymentStarter{ |
||||
startTime: startTime, |
||||
} |
||||
} |
||||
|
||||
// HasStarted returns true if the consensus deployment has started.
|
||||
func (m *MedianTimeDeploymentStarter) HasStarted(blkHeader *wire.BlockHeader) ( |
||||
bool, |
||||
error, |
||||
) { |
||||
switch { |
||||
// If we haven't yet been synchronized with a block clock, then we
|
||||
// can't tell the time, so we'll fail.
|
||||
case m.blockClock == nil: |
||||
return false, ErrNoBlockClock |
||||
// If the time is "zero", then the deployment has always started.
|
||||
case m.startTime.IsZero(): |
||||
return true, nil |
||||
} |
||||
medianTime, err := m.blockClock.PastMedianTime(blkHeader) |
||||
if err != nil { |
||||
return false, err |
||||
} |
||||
// We check both after and equal here as after will fail for equivalent
|
||||
// times, and we want to be inclusive.
|
||||
return medianTime.After(m.startTime) || medianTime.Equal(m.startTime), nil |
||||
} |
||||
|
||||
// MedianTimeDeploymentEnder is a ClockConsensusDeploymentEnder that uses the
|
||||
// median time past of a target block to determine if a deployment has ended.
|
||||
type MedianTimeDeploymentEnder struct { |
||||
blockClock BlockClock |
||||
endTime time.Time |
||||
} |
||||
|
||||
// NewMedianTimeDeploymentEnder returns a new instance of the
|
||||
// MedianTimeDeploymentEnder anchored around the passed endTime. Using a
|
||||
// time.Time instance where IsZero() is true, indicates that a deployment
|
||||
// should be considered to never end.
|
||||
func NewMedianTimeDeploymentEnder(endTime time.Time) *MedianTimeDeploymentEnder { |
||||
return &MedianTimeDeploymentEnder{ |
||||
endTime: endTime, |
||||
} |
||||
} |
||||
|
||||
// HasEnded returns true if the deployment has ended.
|
||||
func (m *MedianTimeDeploymentEnder) HasEnded(blkHeader *wire.BlockHeader) ( |
||||
bool, |
||||
error, |
||||
) { |
||||
switch { |
||||
// If we haven't yet been synchronized with a block clock, then we can't tell
|
||||
// the time, so we'll we haven't yet been synchronized with a block
|
||||
// clock, then w can't tell the time, so we'll fail.
|
||||
case m.blockClock == nil: |
||||
return false, ErrNoBlockClock |
||||
// If the time is "zero", then the deployment never ends.
|
||||
case m.endTime.IsZero(): |
||||
return false, nil |
||||
} |
||||
medianTime, err := m.blockClock.PastMedianTime(blkHeader) |
||||
if err != nil { |
||||
return false, err |
||||
} |
||||
// We check both after and equal here as after will fail for equivalent
|
||||
// times, and we want to be inclusive.
|
||||
return medianTime.After(m.endTime) || medianTime.Equal(m.endTime), nil |
||||
} |
||||
|
||||
// EndTime returns the raw end time of the deployment.
|
||||
func (m *MedianTimeDeploymentEnder) EndTime() time.Time { |
||||
return m.endTime |
||||
} |
||||
|
||||
// SynchronizeClock synchronizes the target ConsensusDeploymentEnder with the
|
||||
// current up-to date BlockClock.
|
||||
func (m *MedianTimeDeploymentEnder) SynchronizeClock(clock BlockClock) { |
||||
m.blockClock = clock |
||||
} |
||||
|
||||
// A compile-time assertion to ensure MedianTimeDeploymentEnder implements the
|
||||
// ClockConsensusDeploymentStarter interface.
|
||||
var _ ClockConsensusDeploymentEnder = (*MedianTimeDeploymentEnder)(nil) |
||||
@ -1,110 +0,0 @@
@@ -1,110 +0,0 @@
|
||||
package chaincfg |
||||
|
||||
import ( |
||||
"time" |
||||
|
||||
"next.orly.dev/pkg/crypto/ec/chainhash" |
||||
"next.orly.dev/pkg/crypto/ec/wire" |
||||
) |
||||
|
||||
var ( |
||||
// genesisCoinbaseTx is the coinbase transaction for the genesis blocks for
|
||||
// the main network, regression test network, and test network (version 3).
|
||||
genesisCoinbaseTx = wire.MsgTx{ |
||||
Version: 1, |
||||
TxIn: []*wire.TxIn{ |
||||
{ |
||||
PreviousOutPoint: wire.OutPoint{ |
||||
Hash: chainhash.Hash{}, |
||||
Index: 0xffffffff, |
||||
}, |
||||
SignatureScript: []byte{ |
||||
0x04, 0xff, 0xff, 0x00, 0x1d, 0x01, 0x04, |
||||
0x45, /* |.......E| */ |
||||
0x54, 0x68, 0x65, 0x20, 0x54, 0x69, 0x6d, |
||||
0x65, /* |The Time| */ |
||||
0x73, 0x20, 0x30, 0x33, 0x2f, 0x4a, 0x61, |
||||
0x6e, /* |s 03/Jan| */ |
||||
0x2f, 0x32, 0x30, 0x30, 0x39, 0x20, 0x43, |
||||
0x68, /* |/2009 Ch| */ |
||||
0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x6f, |
||||
0x72, /* |ancellor| */ |
||||
0x20, 0x6f, 0x6e, 0x20, 0x62, 0x72, 0x69, |
||||
0x6e, /* | on brin| */ |
||||
0x6b, 0x20, 0x6f, 0x66, 0x20, 0x73, 0x65, |
||||
0x63, /* |k of sec|*/ |
||||
0x6f, 0x6e, 0x64, 0x20, 0x62, 0x61, 0x69, |
||||
0x6c, /* |ond bail| */ |
||||
0x6f, 0x75, 0x74, 0x20, 0x66, 0x6f, 0x72, |
||||
0x20, /* |out for |*/ |
||||
0x62, 0x61, 0x6e, 0x6b, 0x73, /* |banks| */ |
||||
}, |
||||
Sequence: 0xffffffff, |
||||
}, |
||||
}, |
||||
TxOut: []*wire.TxOut{ |
||||
{ |
||||
Value: 0x12a05f200, |
||||
PkScript: []byte{ |
||||
0x41, 0x04, 0x67, 0x8a, 0xfd, 0xb0, 0xfe, |
||||
0x55, /* |A.g....U| */ |
||||
0x48, 0x27, 0x19, 0x67, 0xf1, 0xa6, 0x71, |
||||
0x30, /* |H'.g..q0| */ |
||||
0xb7, 0x10, 0x5c, 0xd6, 0xa8, 0x28, 0xe0, |
||||
0x39, /* |..\..(.9| */ |
||||
0x09, 0xa6, 0x79, 0x62, 0xe0, 0xea, 0x1f, |
||||
0x61, /* |..yb...a| */ |
||||
0xde, 0xb6, 0x49, 0xf6, 0xbc, 0x3f, 0x4c, |
||||
0xef, /* |..I..?L.| */ |
||||
0x38, 0xc4, 0xf3, 0x55, 0x04, 0xe5, 0x1e, |
||||
0xc1, /* |8..U....| */ |
||||
0x12, 0xde, 0x5c, 0x38, 0x4d, 0xf7, 0xba, |
||||
0x0b, /* |..\8M...| */ |
||||
0x8d, 0x57, 0x8a, 0x4c, 0x70, 0x2b, 0x6b, |
||||
0xf1, /* |.W.Lp+k.| */ |
||||
0x1d, 0x5f, 0xac, /* |._.| */ |
||||
}, |
||||
}, |
||||
}, |
||||
LockTime: 0, |
||||
} |
||||
// genesisHash is the hash of the first block in the block chain for the main
|
||||
// network (genesis block).
|
||||
genesisHash = chainhash.Hash( |
||||
[chainhash.HashSize]byte{ |
||||
// Make go vet happy.
|
||||
0x6f, 0xe2, 0x8c, 0x0a, 0xb6, 0xf1, 0xb3, 0x72, |
||||
0xc1, 0xa6, 0xa2, 0x46, 0xae, 0x63, 0xf7, 0x4f, |
||||
0x93, 0x1e, 0x83, 0x65, 0xe1, 0x5a, 0x08, 0x9c, |
||||
0x68, 0xd6, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, |
||||
}, |
||||
) |
||||
// genesisMerkleRoot is the hash of the first transaction in the genesis block
|
||||
// for the main network.
|
||||
genesisMerkleRoot = chainhash.Hash( |
||||
[chainhash.HashSize]byte{ |
||||
// Make go vet happy.
|
||||
0x3b, 0xa3, 0xed, 0xfd, 0x7a, 0x7b, 0x12, 0xb2, |
||||
0x7a, 0xc7, 0x2c, 0x3e, 0x67, 0x76, 0x8f, 0x61, |
||||
0x7f, 0xc8, 0x1b, 0xc3, 0x88, 0x8a, 0x51, 0x32, |
||||
0x3a, 0x9f, 0xb8, 0xaa, 0x4b, 0x1e, 0x5e, 0x4a, |
||||
}, |
||||
) |
||||
// genesisBlock defines
|
||||
// genesisBlock defines the genesis block of the block chain which serves as the
|
||||
// public transaction ledger for the main network.
|
||||
genesisBlock = wire.MsgBlock{ |
||||
Header: wire.BlockHeader{ |
||||
Version: 1, |
||||
PrevBlock: chainhash.Hash{}, // 0000000000000000000000000000000000000000000000000000000000000000
|
||||
MerkleRoot: genesisMerkleRoot, // 4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b
|
||||
Timestamp: time.Unix( |
||||
0x495fab29, |
||||
0, |
||||
), // 2009-01-03 18:15:05 +0000 UTC
|
||||
Bits: 0x1d00ffff, // 486604799 [00000000ffff0000000000000000000000000000000000000000000000000000]
|
||||
Nonce: 0x7c2bac1d, // 2083236893
|
||||
}, |
||||
Transactions: []*wire.MsgTx{&genesisCoinbaseTx}, |
||||
} |
||||
) |
||||
@ -1,493 +0,0 @@
@@ -1,493 +0,0 @@
|
||||
// Package chaincfg provides basic parameters for bitcoin chain and testnets.
|
||||
package chaincfg |
||||
|
||||
import ( |
||||
"math/big" |
||||
"time" |
||||
|
||||
"next.orly.dev/pkg/crypto/ec/chainhash" |
||||
"next.orly.dev/pkg/crypto/ec/wire" |
||||
) |
||||
|
||||
var ( |
||||
// bigOne is 1 represented as a big.Int. It is defined here to avoid
|
||||
// the overhead of creating it multiple times.
|
||||
bigOne = big.NewInt(1) |
||||
|
||||
// mainPowLimit is the highest proof of work value a Bitcoin block can
|
||||
// have for the main network. It is the value 2^224 - 1.
|
||||
mainPowLimit = new(big.Int).Sub(new(big.Int).Lsh(bigOne, 224), bigOne) |
||||
) |
||||
|
||||
// Constants that define the deployment offset in the deployments field of the
|
||||
// parameters for each deployment. This is useful to be able to get the details
|
||||
// of a specific deployment by name.
|
||||
const ( |
||||
// DeploymentTestDummy defines the rule change deployment ID for testing
|
||||
// purposes.
|
||||
DeploymentTestDummy = iota |
||||
|
||||
// DeploymentTestDummyMinActivation defines the rule change deployment
|
||||
// ID for testing purposes. This differs from the DeploymentTestDummy
|
||||
// in that it specifies the newer params the taproot fork used for
|
||||
// activation: a custom threshold and a min activation height.
|
||||
DeploymentTestDummyMinActivation |
||||
|
||||
// DeploymentCSV defines the rule change deployment ID for the CSV
|
||||
// soft-fork package. The CSV package includes the deployment of BIPS
|
||||
// 68, 112, and 113.
|
||||
DeploymentCSV |
||||
|
||||
// DeploymentSegwit defines the rule change deployment ID for the
|
||||
// Segregated Witness (segwit) soft-fork package. The segwit package
|
||||
// includes the deployment of BIPS 141, 142, 144, 145, 147 and 173.
|
||||
DeploymentSegwit |
||||
|
||||
// DeploymentTaproot defines the rule change deployment ID for the
|
||||
// Taproot (+Schnorr) soft-fork package. The taproot package includes
|
||||
// the deployment of BIPS 340, 341 and 342.
|
||||
DeploymentTaproot |
||||
|
||||
// NOTE: DefinedDeployments must always come last since it is used to
|
||||
// determine how many defined deployments there currently are.
|
||||
|
||||
// DefinedDeployments is the number of currently defined deployments.
|
||||
DefinedDeployments |
||||
) |
||||
|
||||
// ConsensusDeployment defines details related to a specific consensus rule
|
||||
// change that is voted in. This is part of BIP0009.
|
||||
type ConsensusDeployment struct { |
||||
// BitNumber defines the specific bit number within the block version
|
||||
// this particular soft-fork deployment refers to.
|
||||
BitNumber uint8 |
||||
|
||||
// MinActivationHeight is an optional field that when set (default
|
||||
// value being zero), modifies the traditional BIP 9 state machine by
|
||||
// only transitioning from LockedIn to Active once the block height is
|
||||
// greater than (or equal to) thus specified height.
|
||||
MinActivationHeight uint32 |
||||
|
||||
// CustomActivationThreshold if set (non-zero), will _override_ the
|
||||
// existing RuleChangeActivationThreshold value set at the
|
||||
// network/chain level. This value divided by the active
|
||||
// MinerConfirmationWindow denotes the threshold required for
|
||||
// activation. A value of 1815 block denotes a 90% threshold.
|
||||
CustomActivationThreshold uint32 |
||||
|
||||
// DeploymentStarter is used to determine if the given
|
||||
// ConsensusDeployment has started or not.
|
||||
DeploymentStarter ConsensusDeploymentStarter |
||||
|
||||
// DeploymentEnder is used to determine if the given
|
||||
// ConsensusDeployment has ended or not.
|
||||
DeploymentEnder ConsensusDeploymentEnder |
||||
} |
||||
|
||||
// Checkpoint identifies a known good point in the block chain. Using
|
||||
// checkpoints allows a few optimizations for old blocks during initial download
|
||||
// and also prevents forks from old blocks.
|
||||
//
|
||||
// Each checkpoint is selected based upon several factors. See the
|
||||
// documentation for blockchain.IsCheckpointCandidate for details on the
|
||||
// selection criteria.
|
||||
type Checkpoint struct { |
||||
Height int32 |
||||
Hash *chainhash.Hash |
||||
} |
||||
|
||||
// DNSSeed identifies a DNS seed.
|
||||
type DNSSeed struct { |
||||
// Host defines the hostname of the seed.
|
||||
Host string |
||||
|
||||
// HasFiltering defines whether the seed supports filtering
|
||||
// by service flags (wire.ServiceFlag).
|
||||
HasFiltering bool |
||||
} |
||||
|
||||
// Params defines a Bitcoin network by its parameters. These parameters may be
|
||||
// used by Bitcoin applications to differentiate networks as well as addresses
|
||||
// and keys for one network from those intended for use on another network.
|
||||
type Params struct { |
||||
// Name defines a human-readable identifier for the network.
|
||||
Name string |
||||
|
||||
// Net defines the magic bytes used to identify the network.
|
||||
Net wire.BitcoinNet |
||||
|
||||
// DefaultPort defines the default peer-to-peer port for the network.
|
||||
DefaultPort string |
||||
|
||||
// DNSSeeds defines a list of DNS seeds for the network that are used
|
||||
// as one method to discover peers.
|
||||
DNSSeeds []DNSSeed |
||||
|
||||
// GenesisBlock defines the first block of the chain.
|
||||
GenesisBlock *wire.MsgBlock |
||||
|
||||
// GenesisHash is the starting block hash.
|
||||
GenesisHash *chainhash.Hash |
||||
|
||||
// PowLimit defines the highest allowed proof of work value for a block
|
||||
// as a uint256.
|
||||
PowLimit *big.Int |
||||
|
||||
// PowLimitBits defines the highest allowed proof of work value for a
|
||||
// block in compact form.
|
||||
PowLimitBits uint32 |
||||
|
||||
// PoWNoRetargeting defines whether the network has difficulty
|
||||
// retargeting enabled or not. This should only be set to true for
|
||||
// regtest like networks.
|
||||
PoWNoRetargeting bool |
||||
|
||||
// These fields define the block heights at which the specified softfork
|
||||
// BIP became active.
|
||||
BIP0034Height int32 |
||||
BIP0065Height int32 |
||||
BIP0066Height int32 |
||||
|
||||
// CoinbaseMaturity is the number of blocks required before newly mined
|
||||
// coins (coinbase transactions) can be spent.
|
||||
CoinbaseMaturity uint16 |
||||
|
||||
// SubsidyReductionInterval is the interval of blocks before the subsidy
|
||||
// is reduced.
|
||||
SubsidyReductionInterval int32 |
||||
|
||||
// TargetTimespan is the desired amount of time that should elapse
|
||||
// before the block difficulty requirement is examined to determine how
|
||||
// it should be changed in order to maintain the desired block
|
||||
// generation rate.
|
||||
TargetTimespan time.Duration |
||||
|
||||
// TargetTimePerBlock is the desired amount of time to generate each
|
||||
// block.
|
||||
TargetTimePerBlock time.Duration |
||||
|
||||
// RetargetAdjustmentFactor is the adjustment factor used to limit
|
||||
// the minimum and maximum amount of adjustment that can occur between
|
||||
// difficulty retargets.
|
||||
RetargetAdjustmentFactor int64 |
||||
|
||||
// ReduceMinDifficulty defines whether the network should reduce the
|
||||
// minimum required difficulty after a long enough period of time has
|
||||
// passed without finding a block. This is really only useful for test
|
||||
// networks and should not be set on a main network.
|
||||
ReduceMinDifficulty bool |
||||
|
||||
// MinDiffReductionTime is the amount of time after which the minimum
|
||||
// required difficulty should be reduced when a block hasn't been found.
|
||||
//
|
||||
// NOTE: This only applies if ReduceMinDifficulty is true.
|
||||
MinDiffReductionTime time.Duration |
||||
|
||||
// GenerateSupported specifies whether or not CPU mining is allowed.
|
||||
GenerateSupported bool |
||||
|
||||
// Checkpoints ordered from oldest to newest.
|
||||
Checkpoints []Checkpoint |
||||
|
||||
// These fields are related to voting on consensus rule changes as
|
||||
// defined by BIP0009.
|
||||
//
|
||||
// RuleChangeActivationThreshold is the number of blocks in a threshold
|
||||
// state retarget window for which a positive vote for a rule change
|
||||
// must be cast in order to lock in a rule change. It should typically
|
||||
// be 95% for the main network and 75% for test networks.
|
||||
//
|
||||
// MinerConfirmationWindow is the number of blocks in each threshold
|
||||
// state retarget window.
|
||||
//
|
||||
// Deployments define the specific consensus rule changes to be voted
|
||||
// on.
|
||||
RuleChangeActivationThreshold uint32 |
||||
MinerConfirmationWindow uint32 |
||||
Deployments [DefinedDeployments]ConsensusDeployment |
||||
|
||||
// Mempool parameters
|
||||
RelayNonStdTxs bool |
||||
|
||||
// Human-readable part for Bech32 encoded segwit addresses, as defined
|
||||
// in BIP 173.
|
||||
Bech32HRPSegwit []byte |
||||
|
||||
// Address encoding magics
|
||||
PubKeyHashAddrID byte // First byte of a P2PKH address
|
||||
ScriptHashAddrID byte // First byte of a P2SH address
|
||||
PrivateKeyID byte // First byte of a WIF private key
|
||||
WitnessPubKeyHashAddrID byte // First byte of a P2WPKH address
|
||||
WitnessScriptHashAddrID byte // First byte of a P2WSH address
|
||||
|
||||
// BIP32 hierarchical deterministic extended key magics
|
||||
HDPrivateKeyID [4]byte |
||||
HDPublicKeyID [4]byte |
||||
|
||||
// BIP44 coin type used in the hierarchical deterministic path for
|
||||
// address generation.
|
||||
HDCoinType uint32 |
||||
} |
||||
|
||||
// MainNetParams defines the network parameters for the main Bitcoin network.
|
||||
var MainNetParams = Params{ |
||||
Name: "mainnet", |
||||
Net: wire.MainNet, |
||||
DefaultPort: "8333", |
||||
DNSSeeds: []DNSSeed{ |
||||
{"seed.bitcoin.sipa.be", true}, |
||||
{"dnsseed.bluematt.me", true}, |
||||
{"dnsseed.bitcoin.dashjr.org", false}, |
||||
{"seed.bitcoinstats.com", true}, |
||||
{"seed.bitnodes.io", false}, |
||||
{"seed.bitcoin.jonasschnelli.ch", true}, |
||||
}, |
||||
|
||||
// Chain parameters
|
||||
GenesisBlock: &genesisBlock, |
||||
GenesisHash: &genesisHash, |
||||
PowLimit: mainPowLimit, |
||||
PowLimitBits: 0x1d00ffff, |
||||
BIP0034Height: 227931, // 000000000000024b89b42a942fe0d9fea3bb44ab7bd1b19115dd6a759c0808b8
|
||||
BIP0065Height: 388381, // 000000000000000004c2b624ed5d7756c508d90fd0da2c7c679febfa6c4735f0
|
||||
BIP0066Height: 363725, // 00000000000000000379eaa19dce8c9b722d46ae6a57c2f1a988119488b50931
|
||||
CoinbaseMaturity: 100, |
||||
SubsidyReductionInterval: 210000, |
||||
TargetTimespan: time.Hour * 24 * 14, // 14 days
|
||||
TargetTimePerBlock: time.Minute * 10, // 10 minutes
|
||||
RetargetAdjustmentFactor: 4, // 25% less, 400% more
|
||||
ReduceMinDifficulty: false, |
||||
MinDiffReductionTime: 0, |
||||
GenerateSupported: false, |
||||
|
||||
// Checkpoints ordered from oldest to newest.
|
||||
Checkpoints: []Checkpoint{ |
||||
{ |
||||
11111, |
||||
newHashFromStr("0000000069e244f73d78e8fd29ba2fd2ed618bd6fa2ee92559f542fdb26e7c1d"), |
||||
}, |
||||
{ |
||||
33333, |
||||
newHashFromStr("000000002dd5588a74784eaa7ab0507a18ad16a236e7b1ce69f00d7ddfb5d0a6"), |
||||
}, |
||||
{ |
||||
74000, |
||||
newHashFromStr("0000000000573993a3c9e41ce34471c079dcf5f52a0e824a81e7f953b8661a20"), |
||||
}, |
||||
{ |
||||
105000, |
||||
newHashFromStr("00000000000291ce28027faea320c8d2b054b2e0fe44a773f3eefb151d6bdc97"), |
||||
}, |
||||
{ |
||||
134444, |
||||
newHashFromStr("00000000000005b12ffd4cd315cd34ffd4a594f430ac814c91184a0d42d2b0fe"), |
||||
}, |
||||
{ |
||||
168000, |
||||
newHashFromStr("000000000000099e61ea72015e79632f216fe6cb33d7899acb35b75c8303b763"), |
||||
}, |
||||
{ |
||||
193000, |
||||
newHashFromStr("000000000000059f452a5f7340de6682a977387c17010ff6e6c3bd83ca8b1317"), |
||||
}, |
||||
{ |
||||
210000, |
||||
newHashFromStr("000000000000048b95347e83192f69cf0366076336c639f9b7228e9ba171342e"), |
||||
}, |
||||
{ |
||||
216116, |
||||
newHashFromStr("00000000000001b4f4b433e81ee46494af945cf96014816a4e2370f11b23df4e"), |
||||
}, |
||||
{ |
||||
225430, |
||||
newHashFromStr("00000000000001c108384350f74090433e7fcf79a606b8e797f065b130575932"), |
||||
}, |
||||
{ |
||||
250000, |
||||
newHashFromStr("000000000000003887df1f29024b06fc2200b55f8af8f35453d7be294df2d214"), |
||||
}, |
||||
{ |
||||
267300, |
||||
newHashFromStr("000000000000000a83fbd660e918f218bf37edd92b748ad940483c7c116179ac"), |
||||
}, |
||||
{ |
||||
279000, |
||||
newHashFromStr("0000000000000001ae8c72a0b0c301f67e3afca10e819efa9041e458e9bd7e40"), |
||||
}, |
||||
{ |
||||
300255, |
||||
newHashFromStr("0000000000000000162804527c6e9b9f0563a280525f9d08c12041def0a0f3b2"), |
||||
}, |
||||
{ |
||||
319400, |
||||
newHashFromStr("000000000000000021c6052e9becade189495d1c539aa37c58917305fd15f13b"), |
||||
}, |
||||
{ |
||||
343185, |
||||
newHashFromStr("0000000000000000072b8bf361d01a6ba7d445dd024203fafc78768ed4368554"), |
||||
}, |
||||
{ |
||||
352940, |
||||
newHashFromStr("000000000000000010755df42dba556bb72be6a32f3ce0b6941ce4430152c9ff"), |
||||
}, |
||||
{ |
||||
382320, |
||||
newHashFromStr("00000000000000000a8dc6ed5b133d0eb2fd6af56203e4159789b092defd8ab2"), |
||||
}, |
||||
{ |
||||
400000, |
||||
newHashFromStr("000000000000000004ec466ce4732fe6f1ed1cddc2ed4b328fff5224276e3f6f"), |
||||
}, |
||||
{ |
||||
430000, |
||||
newHashFromStr("000000000000000001868b2bb3a285f3cc6b33ea234eb70facf4dcdf22186b87"), |
||||
}, |
||||
{ |
||||
460000, |
||||
newHashFromStr("000000000000000000ef751bbce8e744ad303c47ece06c8d863e4d417efc258c"), |
||||
}, |
||||
{ |
||||
490000, |
||||
newHashFromStr("000000000000000000de069137b17b8d5a3dfbd5b145b2dcfb203f15d0c4de90"), |
||||
}, |
||||
{ |
||||
520000, |
||||
newHashFromStr("0000000000000000000d26984c0229c9f6962dc74db0a6d525f2f1640396f69c"), |
||||
}, |
||||
{ |
||||
550000, |
||||
newHashFromStr("000000000000000000223b7a2298fb1c6c75fb0efc28a4c56853ff4112ec6bc9"), |
||||
}, |
||||
{ |
||||
560000, |
||||
newHashFromStr("0000000000000000002c7b276daf6efb2b6aa68e2ce3be67ef925b3264ae7122"), |
||||
}, |
||||
{ |
||||
563378, |
||||
newHashFromStr("0000000000000000000f1c54590ee18d15ec70e68c8cd4cfbadb1b4f11697eee"), |
||||
}, |
||||
{ |
||||
597379, |
||||
newHashFromStr("00000000000000000005f8920febd3925f8272a6a71237563d78c2edfdd09ddf"), |
||||
}, |
||||
{ |
||||
623950, |
||||
newHashFromStr("0000000000000000000f2adce67e49b0b6bdeb9de8b7c3d7e93b21e7fc1e819d"), |
||||
}, |
||||
{ |
||||
654683, |
||||
newHashFromStr("0000000000000000000b9d2ec5a352ecba0592946514a92f14319dc2b367fc72"), |
||||
}, |
||||
{ |
||||
691719, |
||||
newHashFromStr("00000000000000000008a89e854d57e5667df88f1cdef6fde2fbca1de5b639ad"), |
||||
}, |
||||
{ |
||||
724466, |
||||
newHashFromStr("000000000000000000052d314a259755ca65944e68df6b12a067ea8f1f5a7091"), |
||||
}, |
||||
{ |
||||
751565, |
||||
newHashFromStr("00000000000000000009c97098b5295f7e5f183ac811fb5d1534040adb93cabd"), |
||||
}, |
||||
}, |
||||
|
||||
// Consensus rule change deployments.
|
||||
//
|
||||
// The miner confirmation window is defined as:
|
||||
// target proof of work timespan / target proof of work spacing
|
||||
RuleChangeActivationThreshold: 1916, // 95% of MinerConfirmationWindow
|
||||
MinerConfirmationWindow: 2016, //
|
||||
Deployments: [DefinedDeployments]ConsensusDeployment{ |
||||
DeploymentTestDummy: { |
||||
BitNumber: 28, |
||||
DeploymentStarter: NewMedianTimeDeploymentStarter( |
||||
time.Unix(11991456010, 0), // January 1, 2008 UTC
|
||||
), |
||||
DeploymentEnder: NewMedianTimeDeploymentEnder( |
||||
time.Unix(1230767999, 0), // December 31, 2008 UTC
|
||||
), |
||||
}, |
||||
DeploymentTestDummyMinActivation: { |
||||
BitNumber: 22, |
||||
CustomActivationThreshold: 1815, // Only needs 90% hash rate.
|
||||
MinActivationHeight: 10_0000, // Can only activate after height 10k.
|
||||
DeploymentStarter: NewMedianTimeDeploymentStarter( |
||||
time.Time{}, // Always available for vote
|
||||
), |
||||
DeploymentEnder: NewMedianTimeDeploymentEnder( |
||||
time.Time{}, // Never expires
|
||||
), |
||||
}, |
||||
DeploymentCSV: { |
||||
BitNumber: 0, |
||||
DeploymentStarter: NewMedianTimeDeploymentStarter( |
||||
time.Unix(1462060800, 0), // May 1st, 2016
|
||||
), |
||||
DeploymentEnder: NewMedianTimeDeploymentEnder( |
||||
time.Unix(1493596800, 0), // May 1st, 2017
|
||||
), |
||||
}, |
||||
DeploymentSegwit: { |
||||
BitNumber: 1, |
||||
DeploymentStarter: NewMedianTimeDeploymentStarter( |
||||
time.Unix(1479168000, 0), // November 15, 2016 UTC
|
||||
), |
||||
DeploymentEnder: NewMedianTimeDeploymentEnder( |
||||
time.Unix(1510704000, 0), // November 15, 2017 UTC.
|
||||
), |
||||
}, |
||||
DeploymentTaproot: { |
||||
BitNumber: 2, |
||||
DeploymentStarter: NewMedianTimeDeploymentStarter( |
||||
time.Unix(1619222400, 0), // April 24th, 2021 UTC.
|
||||
), |
||||
DeploymentEnder: NewMedianTimeDeploymentEnder( |
||||
time.Unix(1628640000, 0), // August 11th, 2021 UTC.
|
||||
), |
||||
CustomActivationThreshold: 1815, // 90%
|
||||
MinActivationHeight: 709_632, |
||||
}, |
||||
}, |
||||
|
||||
// Mempool parameters
|
||||
RelayNonStdTxs: false, |
||||
|
||||
// Human-readable part for Bech32 encoded segwit addresses, as defined in
|
||||
// BIP 173.
|
||||
Bech32HRPSegwit: []byte("bc"), // always bc for main net
|
||||
|
||||
// Address encoding magics
|
||||
PubKeyHashAddrID: 0x00, // starts with 1
|
||||
ScriptHashAddrID: 0x05, // starts with 3
|
||||
PrivateKeyID: 0x80, // starts with 5 (uncompressed) or K (compressed)
|
||||
WitnessPubKeyHashAddrID: 0x06, // starts with p2
|
||||
WitnessScriptHashAddrID: 0x0A, // starts with 7Xh
|
||||
|
||||
// BIP32 hierarchical deterministic extended key magics
|
||||
HDPrivateKeyID: [4]byte{0x04, 0x88, 0xad, 0xe4}, // starts with xprv
|
||||
HDPublicKeyID: [4]byte{0x04, 0x88, 0xb2, 0x1e}, // starts with xpub
|
||||
|
||||
// BIP44 coin type used in the hierarchical deterministic path for
|
||||
// address generation.
|
||||
HDCoinType: 0, |
||||
} |
||||
|
||||
// newHashFromStr converts the passed big-endian hex string into a
|
||||
// chainhash.Hash. It only differs from the one available in chainhash in that
|
||||
// it panics on an error since it will only (and must only) be called with
|
||||
// hard-coded, and therefore known good, hashes.
|
||||
func newHashFromStr(hexStr string) *chainhash.Hash { |
||||
hash, err := chainhash.NewHashFromStr(hexStr) |
||||
if err != nil { |
||||
// Ordinarily I don't like panics in library code since it
|
||||
// can take applications down without them having a chance to
|
||||
// recover which is extremely annoying, however an exception is
|
||||
// being made in this case because the only way this can panic
|
||||
// is if there is an error in the hard-coded hashes. Thus it
|
||||
// will only ever potentially panic on init and therefore is
|
||||
// 100% predictable.
|
||||
panic(err) |
||||
} |
||||
return hash |
||||
} |
||||
@ -1,17 +0,0 @@
@@ -1,17 +0,0 @@
|
||||
# chainhash |
||||
|
||||
# [](http://copyfree.org) |
||||
|
||||
chainhash provides a generic hash type and associated functions that allows the |
||||
specific hash algorithm to be abstracted. |
||||
|
||||
## Installation and Updating |
||||
|
||||
```bash |
||||
$ go get -u mleku.online/git/ec/chainhash |
||||
``` |
||||
|
||||
## License |
||||
|
||||
Package chainhash is licensed under the [copyfree](http://copyfree.org) ISC |
||||
License. |
||||
@ -1,5 +0,0 @@
@@ -1,5 +0,0 @@
|
||||
// Package chainhash provides abstracted hash functionality.
|
||||
//
|
||||
// This package provides a generic hash type and associated functions that
|
||||
// allows the specific hash algorithm to be abstracted.
|
||||
package chainhash |
||||
@ -1,229 +0,0 @@
@@ -1,229 +0,0 @@
|
||||
// Copyright (c) 2013-2016 The btcsuite developers
|
||||
// Copyright (c) 2015 The Decred developers
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package chainhash |
||||
|
||||
import ( |
||||
"encoding/json" |
||||
"fmt" |
||||
|
||||
"github.com/minio/sha256-simd" |
||||
"next.orly.dev/pkg/encoders/hex" |
||||
) |
||||
|
||||
const ( |
||||
// HashSize of array used to store hashes. See Hash.
|
||||
HashSize = 32 |
||||
// MaxHashStringSize is the maximum length of a Hash hash string.
|
||||
MaxHashStringSize = HashSize * 2 |
||||
) |
||||
|
||||
var ( |
||||
// TagBIP0340Challenge is the BIP-0340 tag for challenges.
|
||||
TagBIP0340Challenge = []byte("BIP0340/challenge") |
||||
// TagBIP0340Aux is the BIP-0340 tag for aux data.
|
||||
TagBIP0340Aux = []byte("BIP0340/aux") |
||||
// TagBIP0340Nonce is the BIP-0340 tag for nonces.
|
||||
TagBIP0340Nonce = []byte("BIP0340/nonce") |
||||
// TagTapSighash is the tag used by BIP 341 to generate the sighash
|
||||
// flags.
|
||||
TagTapSighash = []byte("TapSighash") |
||||
// TagTapLeaf is the message tag prefix used to compute the hash
|
||||
// digest of a tapscript leaf.
|
||||
TagTapLeaf = []byte("TapLeaf") |
||||
// TagTapBranch is the message tag prefix used to compute the
|
||||
// hash digest of two tap leaves into a taproot branch node.
|
||||
TagTapBranch = []byte("TapBranch") |
||||
// TagTapTweak is the message tag prefix used to compute the hash tweak
|
||||
// used to enable a public key to commit to the taproot branch root
|
||||
// for the witness program.
|
||||
TagTapTweak = []byte("TapTweak") |
||||
// precomputedTags is a map containing the SHA-256 hash of the BIP-0340
|
||||
// tags.
|
||||
precomputedTags = map[string]Hash{ |
||||
string(TagBIP0340Challenge): sha256.Sum256(TagBIP0340Challenge), |
||||
string(TagBIP0340Aux): sha256.Sum256(TagBIP0340Aux), |
||||
string(TagBIP0340Nonce): sha256.Sum256(TagBIP0340Nonce), |
||||
string(TagTapSighash): sha256.Sum256(TagTapSighash), |
||||
string(TagTapLeaf): sha256.Sum256(TagTapLeaf), |
||||
string(TagTapBranch): sha256.Sum256(TagTapBranch), |
||||
string(TagTapTweak): sha256.Sum256(TagTapTweak), |
||||
} |
||||
) |
||||
|
||||
// ErrHashStrSize describes an error that indicates the caller specified a hash
|
||||
// string that has too many characters.
|
||||
var ErrHashStrSize = fmt.Errorf( |
||||
"max hash string length is %v bytes", |
||||
MaxHashStringSize, |
||||
) |
||||
|
||||
// Hash is used in several of the bitcoin messages and common structures. It
|
||||
// typically represents the double sha256 of data.
|
||||
type Hash [HashSize]byte |
||||
|
||||
// String returns the Hash as the hexadecimal string of the byte-reversed
|
||||
// hash.
|
||||
func (hash Hash) String() string { |
||||
for i := 0; i < HashSize/2; i++ { |
||||
hash[i], hash[HashSize-1-i] = hash[HashSize-1-i], hash[i] |
||||
} |
||||
return hex.Enc(hash[:]) |
||||
} |
||||
|
||||
// CloneBytes returns a copy of the bytes which represent the hash as a byte
|
||||
// slice.
|
||||
//
|
||||
// NOTE: It is generally cheaper to just slice the hash directly thereby reusing
|
||||
// the same bytes rather than calling this method.
|
||||
func (hash *Hash) CloneBytes() []byte { |
||||
newHash := make([]byte, HashSize) |
||||
copy(newHash, hash[:]) |
||||
return newHash |
||||
} |
||||
|
||||
// SetBytes sets the bytes which represent the hash. An error is returned if
|
||||
// the number of bytes passed in is not HashSize.
|
||||
func (hash *Hash) SetBytes(newHash []byte) error { |
||||
nhlen := len(newHash) |
||||
if nhlen != HashSize { |
||||
return fmt.Errorf( |
||||
"invalid hash length of %v, want %v", nhlen, |
||||
HashSize, |
||||
) |
||||
} |
||||
copy(hash[:], newHash) |
||||
return nil |
||||
} |
||||
|
||||
// IsEqual returns true if target is the same as hash.
|
||||
func (hash *Hash) IsEqual(target *Hash) bool { |
||||
if hash == nil && target == nil { |
||||
return true |
||||
} |
||||
if hash == nil || target == nil { |
||||
return false |
||||
} |
||||
return *hash == *target |
||||
} |
||||
|
||||
// MarshalJSON serialises the hash as a JSON appropriate string value.
|
||||
func (hash Hash) MarshalJSON() ([]byte, error) { |
||||
return json.Marshal(hash.String()) |
||||
} |
||||
|
||||
// UnmarshalJSON parses the hash with JSON appropriate string value.
|
||||
func (hash *Hash) UnmarshalJSON(input []byte) error { |
||||
// If the first byte indicates an array, the hash could have been marshalled
|
||||
// using the legacy method and e.g. persisted.
|
||||
if len(input) > 0 && input[0] == '[' { |
||||
return decodeLegacy(hash, input) |
||||
} |
||||
var sh string |
||||
err := json.Unmarshal(input, &sh) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
newHash, err := NewHashFromStr(sh) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
return hash.SetBytes(newHash[:]) |
||||
} |
||||
|
||||
// NewHash returns a new Hash from a byte slice. An error is returned if
|
||||
// the number of bytes passed in is not HashSize.
|
||||
func NewHash(newHash []byte) (*Hash, error) { |
||||
var sh Hash |
||||
err := sh.SetBytes(newHash) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return &sh, err |
||||
} |
||||
|
||||
// TaggedHash implements the tagged hash scheme described in BIP-340. We use
|
||||
// sha-256 to bind a message hash to a specific context using a tag:
|
||||
// sha256(sha256(tag) || sha256(tag) || msg).
|
||||
func TaggedHash(tag []byte, msgs ...[]byte) *Hash { |
||||
// Check to see if we've already pre-computed the hash of the tag. If
|
||||
// so then this'll save us an extra sha256 hash.
|
||||
shaTag, ok := precomputedTags[string(tag)] |
||||
if !ok { |
||||
shaTag = sha256.Sum256(tag) |
||||
} |
||||
// h = sha256(sha256(tag) || sha256(tag) || msg)
|
||||
h := sha256.New() |
||||
h.Write(shaTag[:]) |
||||
h.Write(shaTag[:]) |
||||
for _, msg := range msgs { |
||||
h.Write(msg) |
||||
} |
||||
taggedHash := h.Sum(nil) |
||||
// The function can't error out since the above hash is guaranteed to
|
||||
// be 32 bytes.
|
||||
hash, _ := NewHash(taggedHash) |
||||
return hash |
||||
} |
||||
|
||||
// NewHashFromStr creates a Hash from a hash string. The string should be
|
||||
// the hexadecimal string of a byte-reversed hash, but any missing characters
|
||||
// result in zero padding at the end of the Hash.
|
||||
func NewHashFromStr(hash string) (*Hash, error) { |
||||
ret := new(Hash) |
||||
err := Decode(ret, hash) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return ret, nil |
||||
} |
||||
|
||||
// Decode decodes the byte-reversed hexadecimal string encoding of a Hash to a
|
||||
// destination.
|
||||
func Decode(dst *Hash, src string) error { |
||||
// Return error if hash string is too long.
|
||||
if len(src) > MaxHashStringSize { |
||||
return ErrHashStrSize |
||||
} |
||||
// Hex decoder expects the hash to be a multiple of two. When not, pad
|
||||
// with a leading zero.
|
||||
var srcBytes []byte |
||||
if len(src)%2 == 0 { |
||||
srcBytes = []byte(src) |
||||
} else { |
||||
srcBytes = make([]byte, 1+len(src)) |
||||
srcBytes[0] = '0' |
||||
copy(srcBytes[1:], src) |
||||
} |
||||
// Hex decode the source bytes to a temporary destination.
|
||||
var reversedHash Hash |
||||
_, err := hex.DecAppend( |
||||
reversedHash[HashSize-hex.DecLen(len(srcBytes)):], |
||||
srcBytes, |
||||
) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
// Reverse copy from the temporary hash to destination. Because the
|
||||
// temporary was zeroed, the written result will be correctly padded.
|
||||
for i, b := range reversedHash[:HashSize/2] { |
||||
dst[i], dst[HashSize-1-i] = reversedHash[HashSize-1-i], b |
||||
} |
||||
return nil |
||||
} |
||||
|
||||
// decodeLegacy decodes an Hash that has been encoded with the legacy method
|
||||
// (i.e. represented as a bytes array) to a destination.
|
||||
func decodeLegacy(dst *Hash, src []byte) error { |
||||
var hashBytes []byte |
||||
err := json.Unmarshal(src, &hashBytes) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
if len(hashBytes) != HashSize { |
||||
return ErrHashStrSize |
||||
} |
||||
return dst.SetBytes(hashBytes) |
||||
} |
||||
@ -1,228 +0,0 @@
@@ -1,228 +0,0 @@
|
||||
// Copyright (c) 2013-2016 The btcsuite developers
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package chainhash |
||||
|
||||
import ( |
||||
"testing" |
||||
|
||||
"next.orly.dev/pkg/utils" |
||||
) |
||||
|
||||
// mainNetGenesisHash is the hash of the first block in the block chain for the
|
||||
// main network (genesis block).
|
||||
var mainNetGenesisHash = Hash( |
||||
[HashSize]byte{ |
||||
// Make go vet happy.
|
||||
0x6f, 0xe2, 0x8c, 0x0a, 0xb6, 0xf1, 0xb3, 0x72, |
||||
0xc1, 0xa6, 0xa2, 0x46, 0xae, 0x63, 0xf7, 0x4f, |
||||
0x93, 0x1e, 0x83, 0x65, 0xe1, 0x5a, 0x08, 0x9c, |
||||
0x68, 0xd6, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, |
||||
}, |
||||
) |
||||
|
||||
// TestHash tests the Hash API.
|
||||
func TestHash(t *testing.T) { |
||||
// Hash of block 234439.
|
||||
blockHashStr := "14a0810ac680a3eb3f82edc878cea25ec41d6b790744e5daeef" |
||||
blockHash, err := NewHashFromStr(blockHashStr) |
||||
if err != nil { |
||||
t.Errorf("NewHashFromStr: %v", err) |
||||
} |
||||
// Hash of block 234440 as byte slice.
|
||||
buf := []byte{ |
||||
0x79, 0xa6, 0x1a, 0xdb, 0xc6, 0xe5, 0xa2, 0xe1, |
||||
0x39, 0xd2, 0x71, 0x3a, 0x54, 0x6e, 0xc7, 0xc8, |
||||
0x75, 0x63, 0x2e, 0x75, 0xf1, 0xdf, 0x9c, 0x3f, |
||||
0xa6, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
||||
} |
||||
hash, err := NewHash(buf) |
||||
if err != nil { |
||||
t.Errorf("NewHash: unexpected error %v", err) |
||||
} |
||||
// Ensure proper size.
|
||||
if len(hash) != HashSize { |
||||
t.Errorf( |
||||
"NewHash: hash length mismatch - got: %v, want: %v", |
||||
len(hash), HashSize, |
||||
) |
||||
} |
||||
// Ensure contents match.
|
||||
if !utils.FastEqual(hash[:], buf) { |
||||
t.Errorf( |
||||
"NewHash: hash contents mismatch - got: %v, want: %v", |
||||
hash[:], buf, |
||||
) |
||||
} |
||||
// Ensure contents of hash of block 234440 don't match 234439.
|
||||
if hash.IsEqual(blockHash) { |
||||
t.Errorf( |
||||
"IsEqual: hash contents should not match - got: %v, want: %v", |
||||
hash, blockHash, |
||||
) |
||||
} |
||||
// Set hash from byte slice and ensure contents match.
|
||||
err = hash.SetBytes(blockHash.CloneBytes()) |
||||
if err != nil { |
||||
t.Errorf("SetBytes: %v", err) |
||||
} |
||||
if !hash.IsEqual(blockHash) { |
||||
t.Errorf( |
||||
"IsEqual: hash contents mismatch - got: %v, want: %v", |
||||
hash, blockHash, |
||||
) |
||||
} |
||||
// Ensure nil hashes are handled properly.
|
||||
if !(*Hash)(nil).IsEqual(nil) { |
||||
t.Error("IsEqual: nil hashes should match") |
||||
} |
||||
if hash.IsEqual(nil) { |
||||
t.Error("IsEqual: non-nil hash matches nil hash") |
||||
} |
||||
// Invalid size for SetBytes.
|
||||
err = hash.SetBytes([]byte{0x00}) |
||||
if err == nil { |
||||
t.Errorf("SetBytes: failed to received expected err - got: nil") |
||||
} |
||||
// Invalid size for NewHash.
|
||||
invalidHash := make([]byte, HashSize+1) |
||||
_, err = NewHash(invalidHash) |
||||
if err == nil { |
||||
t.Errorf("NewHash: failed to received expected err - got: nil") |
||||
} |
||||
} |
||||
|
||||
// TestHashString tests the stringized output for hashes.
|
||||
func TestHashString(t *testing.T) { |
||||
// Block 100000 hash.
|
||||
wantStr := "000000000003ba27aa200b1cecaad478d2b00432346c3f1f3986da1afd33e506" |
||||
hash := Hash( |
||||
[HashSize]byte{ |
||||
// Make go vet happy.
|
||||
0x06, 0xe5, 0x33, 0xfd, 0x1a, 0xda, 0x86, 0x39, |
||||
0x1f, 0x3f, 0x6c, 0x34, 0x32, 0x04, 0xb0, 0xd2, |
||||
0x78, 0xd4, 0xaa, 0xec, 0x1c, 0x0b, 0x20, 0xaa, |
||||
0x27, 0xba, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, |
||||
}, |
||||
) |
||||
hashStr := hash.String() |
||||
if hashStr != wantStr { |
||||
t.Errorf( |
||||
"String: wrong hash string - got %v, want %v", |
||||
hashStr, wantStr, |
||||
) |
||||
} |
||||
} |
||||
|
||||
// todo: these fail for some reason
|
||||
// // TestNewHashFromStr executes tests against the NewHashFromStr function.
|
||||
// func TestNewHashFromStr(t *testing.T) {
|
||||
// tests := []struct {
|
||||
// in string
|
||||
// want Hash
|
||||
// err error
|
||||
// }{
|
||||
// // Genesis hash.
|
||||
// {
|
||||
// "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f",
|
||||
// mainNetGenesisHash,
|
||||
// nil,
|
||||
// },
|
||||
// // Genesis hash with stripped leading zeros.
|
||||
// {
|
||||
// "19d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f",
|
||||
// mainNetGenesisHash,
|
||||
// nil,
|
||||
// },
|
||||
// // Empty string.
|
||||
// {
|
||||
// "",
|
||||
// Hash{},
|
||||
// nil,
|
||||
// },
|
||||
// // Single digit hash.
|
||||
// {
|
||||
// "1",
|
||||
// Hash([HashSize]byte{ // Make go vet happy.
|
||||
// 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// }),
|
||||
// nil,
|
||||
// },
|
||||
// // Block 203707 with stripped leading zeros.
|
||||
// {
|
||||
// "3264bc2ac36a60840790ba1d475d01367e7c723da941069e9dc",
|
||||
// Hash([HashSize]byte{ // Make go vet happy.
|
||||
// 0xdc, 0xe9, 0x69, 0x10, 0x94, 0xda, 0x23, 0xc7,
|
||||
// 0xe7, 0x67, 0x13, 0xd0, 0x75, 0xd4, 0xa1, 0x0b,
|
||||
// 0x79, 0x40, 0x08, 0xa6, 0x36, 0xac, 0xc2, 0x4b,
|
||||
// 0x26, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// }),
|
||||
// nil,
|
||||
// },
|
||||
// // Hash string that is too long.
|
||||
// {
|
||||
// "01234567890123456789012345678901234567890123456789012345678912345",
|
||||
// Hash{},
|
||||
// ErrHashStrSize,
|
||||
// },
|
||||
// // Hash string that is contains non-hex chars.
|
||||
// {
|
||||
// "abcdefg",
|
||||
// Hash{},
|
||||
// hex.InvalidByteError('g'),
|
||||
// },
|
||||
// }
|
||||
//
|
||||
// unexpectedErrStr := "NewHashFromStr #%d failed to detect expected error - got: %v want: %v"
|
||||
// unexpectedResultStr := "NewHashFromStr #%d got: %v want: %v"
|
||||
// t.Logf("Running %d tests", len(tests))
|
||||
// for i, test := range tests {
|
||||
// result, err := NewHashFromStr(test.in)
|
||||
// if err != test.err {
|
||||
// t.Errorf(unexpectedErrStr, i, err, test.err)
|
||||
// continue
|
||||
// } else if err != nil {
|
||||
// // Got expected error. Move on to the next test.
|
||||
// continue
|
||||
// }
|
||||
// if !test.want.IsEqual(result) {
|
||||
// t.Errorf(unexpectedResultStr, i, result, &test.want)
|
||||
// continue
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // TestHashJsonMarshal tests json marshal and unmarshal.
|
||||
// func TestHashJsonMarshal(t *testing.T) {
|
||||
// hashStr := "000000000003ba27aa200b1cecaad478d2b00432346c3f1f3986da1afd33e506"
|
||||
// legacyHashStr := []byte("[6,229,51,253,26,218,134,57,31,63,108,52,50,4,176,210,120,212,170,236,28,11,32,170,39,186,3,0,0,0,0,0]")
|
||||
// hash, err := NewHashFromStr(hashStr)
|
||||
// if err != nil {
|
||||
// t.Errorf("NewHashFromStr error:%v, hashStr:%s", err, hashStr)
|
||||
// }
|
||||
// hashBytes, err := json.Marshal(hash)
|
||||
// if err != nil {
|
||||
// t.Errorf("Marshal json error:%v, hash:%v", err, hashBytes)
|
||||
// }
|
||||
// var newHash Hash
|
||||
// err = json.Unmarshal(hashBytes, &newHash)
|
||||
// if err != nil {
|
||||
// t.Errorf("Unmarshal json error:%v, hash:%v", err, hashBytes)
|
||||
// }
|
||||
// if !hash.IsEqual(&newHash) {
|
||||
// t.Errorf("String: wrong hash string - got %v, want %v",
|
||||
// newHash.String(), hashStr)
|
||||
// }
|
||||
// err = newHash.Unmarshal(legacyHashStr)
|
||||
// if err != nil {
|
||||
// t.Errorf("Unmarshal legacy json error:%v, hash:%v", err, legacyHashStr)
|
||||
// }
|
||||
// if !hash.IsEqual(&newHash) {
|
||||
// t.Errorf("String: wrong hash string - got %v, want %v",
|
||||
// newHash.String(), hashStr)
|
||||
// }
|
||||
// }
|
||||
@ -1,33 +0,0 @@
@@ -1,33 +0,0 @@
|
||||
// Copyright (c) 2015 The Decred developers
|
||||
// Copyright (c) 2016-2017 The btcsuite developers
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package chainhash |
||||
|
||||
import ( |
||||
"github.com/minio/sha256-simd" |
||||
) |
||||
|
||||
// HashB calculates hash(b) and returns the resulting bytes.
|
||||
func HashB(b []byte) []byte { |
||||
hash := sha256.Sum256(b) |
||||
return hash[:] |
||||
} |
||||
|
||||
// HashH calculates hash(b) and returns the resulting bytes as a Hash.
|
||||
func HashH(b []byte) Hash { return Hash(sha256.Sum256(b)) } |
||||
|
||||
// DoubleHashB calculates hash(hash(b)) and returns the resulting bytes.
|
||||
func DoubleHashB(b []byte) []byte { |
||||
first := sha256.Sum256(b) |
||||
second := sha256.Sum256(first[:]) |
||||
return second[:] |
||||
} |
||||
|
||||
// DoubleHashH calculates hash(hash(b)) and returns the resulting bytes as a
|
||||
// Hash.
|
||||
func DoubleHashH(b []byte) Hash { |
||||
first := sha256.Sum256(b) |
||||
return sha256.Sum256(first[:]) |
||||
} |
||||
@ -1,323 +0,0 @@
@@ -1,323 +0,0 @@
|
||||
// Copyright (c) 2016 The btcsuite developers
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package chainhash |
||||
|
||||
import ( |
||||
"fmt" |
||||
"testing" |
||||
) |
||||
|
||||
// TestHashFuncs ensures the hash functions which perform hash(b) work as
|
||||
// expected.
|
||||
func TestHashFuncs(t *testing.T) { |
||||
tests := []struct { |
||||
out string |
||||
in string |
||||
}{ |
||||
{ |
||||
"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", |
||||
"", |
||||
}, |
||||
{ |
||||
"ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb", |
||||
"a", |
||||
}, |
||||
{ |
||||
"fb8e20fc2e4c3f248c60c39bd652f3c1347298bb977b8b4d5903b85055620603", |
||||
"ab", |
||||
}, |
||||
{ |
||||
"ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", |
||||
"abc", |
||||
}, |
||||
{ |
||||
"88d4266fd4e6338d13b845fcf289579d209c897823b9217da3e161936f031589", |
||||
"abcd", |
||||
}, |
||||
{ |
||||
"36bbe50ed96841d10443bcb670d6554f0a34b761be67ec9c4a8ad2c0c44ca42c", |
||||
"abcde", |
||||
}, |
||||
{ |
||||
"bef57ec7f53a6d40beb640a780a639c83bc29ac8a9816f1fc6c5c6dcd93c4721", |
||||
"abcdef", |
||||
}, |
||||
{ |
||||
"7d1a54127b222502f5b79b5fb0803061152a44f92b37e23c6527baf665d4da9a", |
||||
"abcdefg", |
||||
}, |
||||
{ |
||||
"9c56cc51b374c3ba189210d5b6d4bf57790d351c96c47c02190ecf1e430635ab", |
||||
"abcdefgh", |
||||
}, |
||||
{ |
||||
"19cc02f26df43cc571bc9ed7b0c4d29224a3ec229529221725ef76d021c8326f", |
||||
"abcdefghi", |
||||
}, |
||||
{ |
||||
"72399361da6a7754fec986dca5b7cbaf1c810a28ded4abaf56b2106d06cb78b0", |
||||
"abcdefghij", |
||||
}, |
||||
{ |
||||
"a144061c271f152da4d151034508fed1c138b8c976339de229c3bb6d4bbb4fce", |
||||
"Discard medicine more than two years old.", |
||||
}, |
||||
{ |
||||
"6dae5caa713a10ad04b46028bf6dad68837c581616a1589a265a11288d4bb5c4", |
||||
"He who has a shady past knows that nice guys finish last.", |
||||
}, |
||||
{ |
||||
"ae7a702a9509039ddbf29f0765e70d0001177914b86459284dab8b348c2dce3f", |
||||
"I wouldn't marry him with a ten foot pole.", |
||||
}, |
||||
{ |
||||
"6748450b01c568586715291dfa3ee018da07d36bb7ea6f180c1af6270215c64f", |
||||
"Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave", |
||||
}, |
||||
{ |
||||
"14b82014ad2b11f661b5ae6a99b75105c2ffac278cd071cd6c05832793635774", |
||||
"The days of the digital watch are numbered. -Tom Stoppard", |
||||
}, |
||||
{ |
||||
"7102cfd76e2e324889eece5d6c41921b1e142a4ac5a2692be78803097f6a48d8", |
||||
"Nepal premier won't resign.", |
||||
}, |
||||
{ |
||||
"23b1018cd81db1d67983c5f7417c44da9deb582459e378d7a068552ea649dc9f", |
||||
"For every action there is an equal and opposite government program.", |
||||
}, |
||||
{ |
||||
"8001f190dfb527261c4cfcab70c98e8097a7a1922129bc4096950e57c7999a5a", |
||||
"His money is twice tainted: 'taint yours and 'taint mine.", |
||||
}, |
||||
{ |
||||
"8c87deb65505c3993eb24b7a150c4155e82eee6960cf0c3a8114ff736d69cad5", |
||||
"There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977", |
||||
}, |
||||
{ |
||||
"bfb0a67a19cdec3646498b2e0f751bddc41bba4b7f30081b0b932aad214d16d7", |
||||
"It's a tiny change to the code and not completely disgusting. - Bob Manchek", |
||||
}, |
||||
{ |
||||
"7f9a0b9bf56332e19f5a0ec1ad9c1425a153da1c624868fda44561d6b74daf36", |
||||
"size: a.out: bad magic", |
||||
}, |
||||
{ |
||||
"b13f81b8aad9e3666879af19886140904f7f429ef083286195982a7588858cfc", |
||||
"The major problem is with sendmail. -Mark Horton", |
||||
}, |
||||
{ |
||||
"b26c38d61519e894480c70c8374ea35aa0ad05b2ae3d6674eec5f52a69305ed4", |
||||
"Give me a rock, paper and scissors and I will move the world. CCFestoon", |
||||
}, |
||||
{ |
||||
"049d5e26d4f10222cd841a119e38bd8d2e0d1129728688449575d4ff42b842c1", |
||||
"If the enemy is within range, then so are you.", |
||||
}, |
||||
{ |
||||
"0e116838e3cc1c1a14cd045397e29b4d087aa11b0853fc69ec82e90330d60949", |
||||
"It's well we cannot hear the screams/That we create in others' dreams.", |
||||
}, |
||||
{ |
||||
"4f7d8eb5bcf11de2a56b971021a444aa4eafd6ecd0f307b5109e4e776cd0fe46", |
||||
"You remind me of a TV show, but that's all right: I watch it anyway.", |
||||
}, |
||||
{ |
||||
"61c0cc4c4bd8406d5120b3fb4ebc31ce87667c162f29468b3c779675a85aebce", |
||||
"C is as portable as Stonehedge!!", |
||||
}, |
||||
{ |
||||
"1fb2eb3688093c4a3f80cd87a5547e2ce940a4f923243a79a2a1e242220693ac", |
||||
"Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley", |
||||
}, |
||||
{ |
||||
"395585ce30617b62c80b93e8208ce866d4edc811a177fdb4b82d3911d8696423", |
||||
"The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction. Lewis-Randall Rule", |
||||
}, |
||||
{ |
||||
"4f9b189a13d030838269dce846b16a1ce9ce81fe63e65de2f636863336a98fe6", |
||||
"How can you write a big system without C++? -Paul Glick", |
||||
}, |
||||
} |
||||
|
||||
// Ensure the hash function which returns a byte slice returns the
|
||||
// expected result.
|
||||
for _, test := range tests { |
||||
h := fmt.Sprintf("%x", HashB([]byte(test.in))) |
||||
if h != test.out { |
||||
t.Errorf("HashB(%q) = %s, want %s", test.in, h, test.out) |
||||
continue |
||||
} |
||||
} |
||||
// Ensure the hash function which returns a Hash returns the expected
|
||||
// result.
|
||||
for _, test := range tests { |
||||
hash := HashH([]byte(test.in)) |
||||
h := fmt.Sprintf("%x", hash[:]) |
||||
if h != test.out { |
||||
t.Errorf("HashH(%q) = %s, want %s", test.in, h, test.out) |
||||
continue |
||||
} |
||||
} |
||||
} |
||||
|
||||
// TestDoubleHashFuncs ensures the hash functions which perform hash(hash(b))
|
||||
// work as expected.
|
||||
func TestDoubleHashFuncs(t *testing.T) { |
||||
tests := []struct { |
||||
out string |
||||
in string |
||||
}{ |
||||
{ |
||||
"5df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c9456", |
||||
"", |
||||
}, |
||||
{ |
||||
"bf5d3affb73efd2ec6c36ad3112dd933efed63c4e1cbffcfa88e2759c144f2d8", |
||||
"a", |
||||
}, |
||||
{ |
||||
"a1ff8f1856b5e24e32e3882edd4a021f48f28a8b21854b77fdef25a97601aace", |
||||
"ab", |
||||
}, |
||||
{ |
||||
"4f8b42c22dd3729b519ba6f68d2da7cc5b2d606d05daed5ad5128cc03e6c6358", |
||||
"abc", |
||||
}, |
||||
{ |
||||
"7e9c158ecd919fa439a7a214c9fc58b85c3177fb1613bdae41ee695060e11bc6", |
||||
"abcd", |
||||
}, |
||||
{ |
||||
"1d72b6eb7ba8b9709c790b33b40d8c46211958e13cf85dbcda0ed201a99f2fb9", |
||||
"abcde", |
||||
}, |
||||
{ |
||||
"ce65d4756128f0035cba4d8d7fae4e9fa93cf7fdf12c0f83ee4a0e84064bef8a", |
||||
"abcdef", |
||||
}, |
||||
{ |
||||
"dad6b965ad86b880ceb6993f98ebeeb242de39f6b87a458c6510b5a15ff7bbf1", |
||||
"abcdefg", |
||||
}, |
||||
{ |
||||
"b9b12e7125f73fda20b8c4161fb9b4b146c34cf88595a1e0503ca2cf44c86bc4", |
||||
"abcdefgh", |
||||
}, |
||||
{ |
||||
"546db09160636e98405fbec8464a84b6464b32514db259e235eae0445346ffb7", |
||||
"abcdefghi", |
||||
}, |
||||
{ |
||||
"27635cf23fdf8a10f4cb2c52ade13038c38718c6d7ca716bfe726111a57ad201", |
||||
"abcdefghij", |
||||
}, |
||||
{ |
||||
"ae0d8e0e7c0336f0c3a72cefa4f24b625a6a460417a921d066058a0b81e23429", |
||||
"Discard medicine more than two years old.", |
||||
}, |
||||
{ |
||||
"eeb56d02cf638f87ea8f11ebd5b0201afcece984d87be458578d3cfb51978f1b", |
||||
"He who has a shady past knows that nice guys finish last.", |
||||
}, |
||||
{ |
||||
"dc640bf529608a381ea7065ecbcd0443b95f6e4c008de6e134aff1d36bd4b9d8", |
||||
"I wouldn't marry him with a ten foot pole.", |
||||
}, |
||||
{ |
||||
"42e54375e60535eb07fc15c6350e10f2c22526f84db1d6f6bba925e154486f33", |
||||
"Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave", |
||||
}, |
||||
{ |
||||
"4ed6aa9b88c84afbf928710b03714de69e2ad967c6a78586069adcb4c470d150", |
||||
"The days of the digital watch are numbered. -Tom Stoppard", |
||||
}, |
||||
{ |
||||
"590c24d1877c1919fad12fe01a8796999e9d20cfbf9bc9bc72fa0bd69f0b04dd", |
||||
"Nepal premier won't resign.", |
||||
}, |
||||
{ |
||||
"37d270687ee8ebafcd3c1a32f56e1e1304b3c93f252cb637d57a66d59c475eca", |
||||
"For every action there is an equal and opposite government program.", |
||||
}, |
||||
{ |
||||
"306828fd89278838bb1c544c3032a1fd25ea65c40bba586437568828a5fbe944", |
||||
"His money is twice tainted: 'taint yours and 'taint mine.", |
||||
}, |
||||
{ |
||||
"49965777eac71faf1e2fb0f6b239ba2fae770977940fd827bcbfe15def6ded53", |
||||
"There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977", |
||||
}, |
||||
{ |
||||
"df99ee4e87dd3fb07922dee7735997bbae8f26db20c86137d4219fc4a37b77c3", |
||||
"It's a tiny change to the code and not completely disgusting. - Bob Manchek", |
||||
}, |
||||
{ |
||||
"920667c84a15b5ee3df4620169f5c0ec930cea0c580858e50e68848871ed65b4", |
||||
"size: a.out: bad magic", |
||||
}, |
||||
{ |
||||
"5e817fe20848a4a3932db68e90f8d54ec1b09603f0c99fdc051892b776acd462", |
||||
"The major problem is with sendmail. -Mark Horton", |
||||
}, |
||||
{ |
||||
"6a9d47248ed38852f5f4b2e37e7dfad0ce8d1da86b280feef94ef267e468cff2", |
||||
"Give me a rock, paper and scissors and I will move the world. CCFestoon", |
||||
}, |
||||
{ |
||||
"2e7aa1b362c94efdbff582a8bd3f7f61c8ce4c25bbde658ef1a7ae1010e2126f", |
||||
"If the enemy is within range, then so are you.", |
||||
}, |
||||
{ |
||||
"e6729d51240b1e1da76d822fd0c55c75e409bcb525674af21acae1f11667c8ca", |
||||
"It's well we cannot hear the screams/That we create in others' dreams.", |
||||
}, |
||||
{ |
||||
"09945e4d2743eb669f85e4097aa1cc39ea680a0b2ae2a65a42a5742b3b809610", |
||||
"You remind me of a TV show, but that's all right: I watch it anyway.", |
||||
}, |
||||
{ |
||||
"1018d8b2870a974887c5174360f0fbaf27958eef15b24522a605c5dae4ae0845", |
||||
"C is as portable as Stonehedge!!", |
||||
}, |
||||
{ |
||||
"97c76b83c6645c78c261dcdc55d44af02d9f1df8057f997fd08c310c903624d5", |
||||
"Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley", |
||||
}, |
||||
{ |
||||
"6bcbf25469e9544c5b5806b24220554fedb6695ba9b1510a76837414f7adb113", |
||||
"The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction. Lewis-Randall Rule", |
||||
}, |
||||
{ |
||||
"1041988b06835481f0845be2a54f4628e1da26145b2de7ad1be3bb643cef9d4f", |
||||
"How can you write a big system without C++? -Paul Glick", |
||||
}, |
||||
} |
||||
// Ensure the hash function which returns a byte slice returns the
|
||||
// expected result.
|
||||
for _, test := range tests { |
||||
h := fmt.Sprintf("%x", DoubleHashB([]byte(test.in))) |
||||
if h != test.out { |
||||
t.Errorf( |
||||
"DoubleHashB(%q) = %s, want %s", test.in, h, |
||||
test.out, |
||||
) |
||||
continue |
||||
} |
||||
} |
||||
// Ensure the hash function which returns a Hash returns the expected
|
||||
// result.
|
||||
for _, test := range tests { |
||||
hash := DoubleHashH([]byte(test.in)) |
||||
h := fmt.Sprintf("%x", hash[:]) |
||||
if h != test.out { |
||||
t.Errorf( |
||||
"DoubleHashH(%q) = %s, want %s", test.in, h, |
||||
test.out, |
||||
) |
||||
continue |
||||
} |
||||
} |
||||
} |
||||
@ -1,16 +0,0 @@
@@ -1,16 +0,0 @@
|
||||
// Copyright (c) 2015-2016 The btcsuite developers
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package btcec |
||||
|
||||
import ( |
||||
"next.orly.dev/pkg/crypto/ec/secp256k1" |
||||
) |
||||
|
||||
// GenerateSharedSecret generates a shared secret based on a secret key and a
|
||||
// public key using Diffie-Hellman key exchange (ECDH) (RFC 4753).
|
||||
// RFC5903 Section 9 states we should only return x.
|
||||
func GenerateSharedSecret(privkey *SecretKey, pubkey *PublicKey) []byte { |
||||
return secp256k1.GenerateSharedSecret(privkey, pubkey) |
||||
} |
||||
@ -1,32 +0,0 @@
@@ -1,32 +0,0 @@
|
||||
// Copyright (c) 2015-2016 The btcsuite developers
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package btcec |
||||
|
||||
import ( |
||||
"testing" |
||||
|
||||
"next.orly.dev/pkg/utils" |
||||
) |
||||
|
||||
func TestGenerateSharedSecret(t *testing.T) { |
||||
privKey1, err := NewSecretKey() |
||||
if err != nil { |
||||
t.Errorf("secret key generation error: %s", err) |
||||
return |
||||
} |
||||
privKey2, err := NewSecretKey() |
||||
if err != nil { |
||||
t.Errorf("secret key generation error: %s", err) |
||||
return |
||||
} |
||||
secret1 := GenerateSharedSecret(privKey1, privKey2.PubKey()) |
||||
secret2 := GenerateSharedSecret(privKey2, privKey1.PubKey()) |
||||
if !utils.FastEqual(secret1, secret2) { |
||||
t.Errorf( |
||||
"ECDH failed, secrets mismatch - first: %x, second: %x", |
||||
secret1, secret2, |
||||
) |
||||
} |
||||
} |
||||
@ -1,111 +0,0 @@
@@ -1,111 +0,0 @@
|
||||
// Copyright (c) 2015-2021 The btcsuite developers
|
||||
// Copyright (c) 2015-2021 The Decred developers
|
||||
|
||||
package btcec |
||||
|
||||
import ( |
||||
"fmt" |
||||
|
||||
"next.orly.dev/pkg/crypto/ec/secp256k1" |
||||
) |
||||
|
||||
// JacobianPoint is an element of the group formed by the secp256k1 curve in
|
||||
// Jacobian projective coordinates and thus represents a point on the curve.
|
||||
type JacobianPoint = secp256k1.JacobianPoint |
||||
|
||||
// infinityPoint is the jacobian representation of the point at infinity.
|
||||
var infinityPoint JacobianPoint |
||||
|
||||
// MakeJacobianPoint returns a Jacobian point with the provided X, Y, and Z
|
||||
// coordinates.
|
||||
func MakeJacobianPoint(x, y, z *FieldVal) JacobianPoint { |
||||
return secp256k1.MakeJacobianPoint(x, y, z) |
||||
} |
||||
|
||||
// AddNonConst adds the passed Jacobian points together and stores the result
|
||||
// in the provided result param in *non-constant* time.
|
||||
func AddNonConst(p1, p2, result *JacobianPoint) { |
||||
secp256k1.AddNonConst(p1, p2, result) |
||||
} |
||||
|
||||
// DecompressY attempts to calculate the Y coordinate for the given X
|
||||
// coordinate such that the result pair is a point on the secp256k1 curve. It
|
||||
// adjusts Y based on the desired oddness and returns whether or not it was
|
||||
// successful since not all X coordinates are valid.
|
||||
//
|
||||
// The magnitude of the provided X coordinate field val must be a max of 8 for
|
||||
// a correct result. The resulting Y field val will have a max magnitude of 2.
|
||||
func DecompressY(x *FieldVal, odd bool, resultY *FieldVal) bool { |
||||
return secp256k1.DecompressY(x, odd, resultY) |
||||
} |
||||
|
||||
// DoubleNonConst doubles the passed Jacobian point and stores the result in
|
||||
// the provided result parameter in *non-constant* time.
|
||||
//
|
||||
// NOTE: The point must be normalized for this function to return the correct
|
||||
// result. The resulting point will be normalized.
|
||||
func DoubleNonConst(p, result *JacobianPoint) { |
||||
secp256k1.DoubleNonConst(p, result) |
||||
} |
||||
|
||||
// ScalarBaseMultNonConst multiplies k*G where G is the base point of the group
|
||||
// and k is a big endian integer. The result is stored in Jacobian coordinates
|
||||
// (x1, y1, z1).
|
||||
//
|
||||
// NOTE: The resulting point will be normalized.
|
||||
func ScalarBaseMultNonConst(k *ModNScalar, result *JacobianPoint) { |
||||
secp256k1.ScalarBaseMultNonConst(k, result) |
||||
} |
||||
|
||||
// ScalarMultNonConst multiplies k*P where k is a big endian integer modulo the
|
||||
// curve order and P is a point in Jacobian projective coordinates and stores
|
||||
// the result in the provided Jacobian point.
|
||||
//
|
||||
// NOTE: The point must be normalized for this function to return the correct
|
||||
// result. The resulting point will be normalized.
|
||||
func ScalarMultNonConst(k *ModNScalar, point, result *JacobianPoint) { |
||||
secp256k1.ScalarMultNonConst(k, point, result) |
||||
} |
||||
|
||||
// ParseJacobian parses a byte slice point as a secp256k1.Publickey and returns the
|
||||
// pubkey as a JacobianPoint. If the nonce is a zero slice, the infinityPoint
|
||||
// is returned.
|
||||
func ParseJacobian(point []byte) (JacobianPoint, error) { |
||||
var result JacobianPoint |
||||
if len(point) != 33 { |
||||
str := fmt.Sprintf( |
||||
"invalid nonce: invalid length: %v", |
||||
len(point), |
||||
) |
||||
return JacobianPoint{}, makeError(secp256k1.ErrPubKeyInvalidLen, str) |
||||
} |
||||
if point[0] == 0x00 { |
||||
return infinityPoint, nil |
||||
} |
||||
noncePk, err := secp256k1.ParsePubKey(point) |
||||
if err != nil { |
||||
return JacobianPoint{}, err |
||||
} |
||||
noncePk.AsJacobian(&result) |
||||
return result, nil |
||||
} |
||||
|
||||
// JacobianToByteSlice converts the passed JacobianPoint to a Pubkey
|
||||
// and serializes that to a byte slice. If the JacobianPoint is the infinity
|
||||
// point, a zero slice is returned.
|
||||
func JacobianToByteSlice(point JacobianPoint) []byte { |
||||
if point.X == infinityPoint.X && point.Y == infinityPoint.Y { |
||||
return make([]byte, 33) |
||||
} |
||||
point.ToAffine() |
||||
return NewPublicKey( |
||||
&point.X, &point.Y, |
||||
).SerializeCompressed() |
||||
} |
||||
|
||||
// GeneratorJacobian sets the passed JacobianPoint to the Generator Point.
|
||||
func GeneratorJacobian(jacobian *JacobianPoint) { |
||||
var k ModNScalar |
||||
k.SetInt(1) |
||||
ScalarBaseMultNonConst(&k, jacobian) |
||||
} |
||||
@ -1,19 +0,0 @@
@@ -1,19 +0,0 @@
|
||||
// Copyright (c) 2013-2014 The btcsuite developers
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package btcec implements support for the elliptic curves needed for bitcoin.
|
||||
//
|
||||
// Bitcoin uses elliptic curve cryptography using koblitz curves
|
||||
// (specifically secp256k1) for cryptographic functions. See
|
||||
// http://www.secg.org/collateral/sec2_final.pdf for details on the
|
||||
// standard.
|
||||
//
|
||||
// This package provides the data structures and functions implementing the
|
||||
// crypto/elliptic Curve interface in order to permit using these curves
|
||||
// with the standard crypto/ecdsa package provided with go. Helper
|
||||
// functionality is provided to parse signatures and public keys from
|
||||
// standard formats. It was designed for use with btcd, but should be
|
||||
// general enough for other uses of elliptic curve crypto. It was originally based
|
||||
// on some initial work by ThePiachu, but has significantly diverged since then.
|
||||
package btcec |
||||
@ -1,27 +0,0 @@
@@ -1,27 +0,0 @@
|
||||
# ecdsa |
||||
|
||||
[](http://copyfree.org) |
||||
[](https://pkg.go.dev/mleku.online/git/ec/secp/ecdsa) |
||||
|
||||
Package ecdsa provides secp256k1-optimized ECDSA signing and verification. |
||||
|
||||
This package provides data structures and functions necessary to produce and |
||||
verify deterministic canonical signatures in accordance with RFC6979 and |
||||
BIP0062, optimized specifically for the secp256k1 curve using the Elliptic Curve |
||||
Digital Signature Algorithm (ECDSA), as defined in FIPS 186-3. See |
||||
https://www.secg.org/sec2-v2.pdf (also found here |
||||
at [sec2-v2.pdf](../sec2-v2.pdf)) for details on the secp256k1 standard. |
||||
|
||||
It also provides functions to parse and serialize the ECDSA signatures with the |
||||
more strict Distinguished Encoding Rules (DER) of ISO/IEC 8825-1 and some |
||||
additional restrictions specific to secp256k1. |
||||
|
||||
In addition, it supports a custom "compact" signature format which allows |
||||
efficient recovery of the public key from a given valid signature and message |
||||
hash combination. |
||||
|
||||
A comprehensive suite of tests is provided to ensure proper functionality. |
||||
|
||||
## License |
||||
|
||||
Package ecdsa is licensed under the [copyfree](http://copyfree.org) ISC License. |
||||
@ -1,169 +0,0 @@
@@ -1,169 +0,0 @@
|
||||
// Copyright 2013-2016 The btcsuite developers
|
||||
// Copyright (c) 2015-2022 The Decred developers
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package ecdsa |
||||
|
||||
import ( |
||||
"testing" |
||||
|
||||
"next.orly.dev/pkg/crypto/ec/secp256k1" |
||||
"next.orly.dev/pkg/encoders/hex" |
||||
) |
||||
|
||||
// hexToModNScalar converts the passed hex string into a ModNScalar and will
|
||||
// panic if there is an error. This is only provided for the hard-coded
|
||||
// constants so errors in the source code can be detected. It will only (and
|
||||
// must only) be called with hard-coded values.
|
||||
func hexToModNScalar(s string) *secp256k1.ModNScalar { |
||||
b, err := hex.Dec(s) |
||||
if err != nil { |
||||
panic("invalid hex in source file: " + s) |
||||
} |
||||
var scalar secp256k1.ModNScalar |
||||
if overflow := scalar.SetByteSlice(b); overflow { |
||||
panic("hex in source file overflows mod N scalar: " + s) |
||||
} |
||||
return &scalar |
||||
} |
||||
|
||||
// hexToFieldVal converts the passed hex string into a FieldVal and will panic
|
||||
// if there is an error. This is only provided for the hard-coded constants so
|
||||
// errors in the source code can be detected. It will only (and must only) be
|
||||
// called with hard-coded values.
|
||||
func hexToFieldVal(s string) *secp256k1.FieldVal { |
||||
b, err := hex.Dec(s) |
||||
if err != nil { |
||||
panic("invalid hex in source file: " + s) |
||||
} |
||||
var f secp256k1.FieldVal |
||||
if overflow := f.SetByteSlice(b); overflow { |
||||
panic("hex in source file overflows mod P: " + s) |
||||
} |
||||
return &f |
||||
} |
||||
|
||||
// BenchmarkSigVerify benchmarks how long it takes the secp256k1 curve to
|
||||
// verify signatures.
|
||||
func BenchmarkSigVerify(b *testing.B) { |
||||
// Randomly generated keypair.
|
||||
// Secret key: 9e0699c91ca1e3b7e3c9ba71eb71c89890872be97576010fe593fbf3fd57e66d
|
||||
pubKey := secp256k1.NewPublicKey( |
||||
hexToFieldVal("d2e670a19c6d753d1a6d8b20bd045df8a08fb162cf508956c31268c6d81ffdab"), |
||||
hexToFieldVal("ab65528eefbb8057aa85d597258a3fbd481a24633bc9b47a9aa045c91371de52"), |
||||
) |
||||
// Double sha256 of by{0x01, 0x02, 0x03, 0x04}
|
||||
msgHash := hexToBytes("8de472e2399610baaa7f84840547cd409434e31f5d3bd71e4d947f283874f9c0") |
||||
sig := NewSignature( |
||||
hexToModNScalar("fef45d2892953aa5bbcdb057b5e98b208f1617a7498af7eb765574e29b5d9c2c"), |
||||
hexToModNScalar("d47563f52aac6b04b55de236b7c515eb9311757db01e02cff079c3ca6efb063f"), |
||||
) |
||||
if !sig.Verify(msgHash, pubKey) { |
||||
b.Errorf("Signature failed to verify") |
||||
return |
||||
} |
||||
b.ReportAllocs() |
||||
b.ResetTimer() |
||||
for i := 0; i < b.N; i++ { |
||||
sig.Verify(msgHash, pubKey) |
||||
} |
||||
} |
||||
|
||||
// BenchmarkSign benchmarks how long it takes to sign a message.
|
||||
func BenchmarkSign(b *testing.B) { |
||||
// Randomly generated keypair.
|
||||
d := hexToModNScalar("9e0699c91ca1e3b7e3c9ba71eb71c89890872be97576010fe593fbf3fd57e66d") |
||||
secKey := secp256k1.NewSecretKey(d) |
||||
// blake256 of by{0x01, 0x02, 0x03, 0x04}.
|
||||
msgHash := hexToBytes("c301ba9de5d6053caad9f5eb46523f007702add2c62fa39de03146a36b8026b7") |
||||
b.ReportAllocs() |
||||
b.ResetTimer() |
||||
for i := 0; i < b.N; i++ { |
||||
signRFC6979(secKey, msgHash) |
||||
} |
||||
} |
||||
|
||||
// BenchmarkSigSerialize benchmarks how long it takes to serialize a typical
|
||||
// signature with the strict DER encoding.
|
||||
func BenchmarkSigSerialize(b *testing.B) { |
||||
// Randomly generated keypair.
|
||||
// Secret key: 9e0699c91ca1e3b7e3c9ba71eb71c89890872be97576010fe593fbf3fd57e66d
|
||||
// Signature for double sha256 of by{0x01, 0x02, 0x03, 0x04}.
|
||||
sig := NewSignature( |
||||
hexToModNScalar("fef45d2892953aa5bbcdb057b5e98b208f1617a7498af7eb765574e29b5d9c2c"), |
||||
hexToModNScalar("d47563f52aac6b04b55de236b7c515eb9311757db01e02cff079c3ca6efb063f"), |
||||
) |
||||
b.ReportAllocs() |
||||
b.ResetTimer() |
||||
for i := 0; i < b.N; i++ { |
||||
sig.Serialize() |
||||
} |
||||
} |
||||
|
||||
// BenchmarkNonceRFC6979 benchmarks how long it takes to generate a
|
||||
// deterministic nonce according to RFC6979.
|
||||
func BenchmarkNonceRFC6979(b *testing.B) { |
||||
// Randomly generated keypair.
|
||||
// Secret key: 9e0699c91ca1e3b7e3c9ba71eb71c89890872be97576010fe593fbf3fd57e66d
|
||||
// X: d2e670a19c6d753d1a6d8b20bd045df8a08fb162cf508956c31268c6d81ffdab
|
||||
// Y: ab65528eefbb8057aa85d597258a3fbd481a24633bc9b47a9aa045c91371de52
|
||||
secKeyStr := "9e0699c91ca1e3b7e3c9ba71eb71c89890872be97576010fe593fbf3fd57e66d" |
||||
secKey := hexToBytes(secKeyStr) |
||||
// BLAKE-256 of by{0x01, 0x02, 0x03, 0x04}.
|
||||
msgHash := hexToBytes("c301ba9de5d6053caad9f5eb46523f007702add2c62fa39de03146a36b8026b7") |
||||
b.ReportAllocs() |
||||
b.ResetTimer() |
||||
var noElideNonce *secp256k1.ModNScalar |
||||
for i := 0; i < b.N; i++ { |
||||
noElideNonce = secp256k1.NonceRFC6979(secKey, msgHash, nil, nil, 0) |
||||
} |
||||
_ = noElideNonce |
||||
} |
||||
|
||||
// BenchmarkSignCompact benchmarks how long it takes to produce a compact
|
||||
// signature for a message.
|
||||
func BenchmarkSignCompact(b *testing.B) { |
||||
d := hexToModNScalar("9e0699c91ca1e3b7e3c9ba71eb71c89890872be97576010fe593fbf3fd57e66d") |
||||
secKey := secp256k1.NewSecretKey(d) |
||||
// blake256 of by{0x01, 0x02, 0x03, 0x04}.
|
||||
msgHash := hexToBytes("c301ba9de5d6053caad9f5eb46523f007702add2c62fa39de03146a36b8026b7") |
||||
b.ReportAllocs() |
||||
b.ResetTimer() |
||||
for i := 0; i < b.N; i++ { |
||||
_ = SignCompact(secKey, msgHash, true) |
||||
} |
||||
} |
||||
|
||||
// BenchmarkRecoverCompact benchmarks how long it takes to recover a public key
|
||||
// given a compact signature and message.
|
||||
func BenchmarkRecoverCompact(b *testing.B) { |
||||
// Secret key: 9e0699c91ca1e3b7e3c9ba71eb71c89890872be97576010fe593fbf3fd57e66d
|
||||
wantPubKey := secp256k1.NewPublicKey( |
||||
hexToFieldVal("d2e670a19c6d753d1a6d8b20bd045df8a08fb162cf508956c31268c6d81ffdab"), |
||||
hexToFieldVal("ab65528eefbb8057aa85d597258a3fbd481a24633bc9b47a9aa045c91371de52"), |
||||
) |
||||
compactSig := hexToBytes( |
||||
"205978b7896bc71676ba2e459882a8f52e1299449596c4f" + |
||||
"93c59bf1fbfa2f9d3b76ecd0c99406f61a6de2bb5a8937c061c176ecf381d0231e0d" + |
||||
"af73b922c8952c7", |
||||
) |
||||
// blake256 of by{0x01, 0x02, 0x03, 0x04}.
|
||||
msgHash := hexToBytes("c301ba9de5d6053caad9f5eb46523f007702add2c62fa39de03146a36b8026b7") |
||||
// Ensure a valid compact signature is being benchmarked.
|
||||
pubKey, wasCompressed, err := RecoverCompact(compactSig, msgHash) |
||||
if err != nil { |
||||
b.Fatalf("unexpected err: %v", err) |
||||
} |
||||
if !wasCompressed { |
||||
b.Fatal("recover claims uncompressed pubkey") |
||||
} |
||||
if !pubKey.IsEqual(wantPubKey) { |
||||
b.Fatal("recover returned unexpected pubkey") |
||||
} |
||||
b.ReportAllocs() |
||||
b.ResetTimer() |
||||
for i := 0; i < b.N; i++ { |
||||
_, _, _ = RecoverCompact(compactSig, msgHash) |
||||
} |
||||
} |
||||
@ -1,40 +0,0 @@
@@ -1,40 +0,0 @@
|
||||
// Copyright (c) 2020-2023 The Decred developers
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package ecdsa provides secp256k1-optimized ECDSA signing and verification.
|
||||
//
|
||||
// This package provides data structures and functions necessary to produce and
|
||||
// verify deterministic canonical signatures in accordance with RFC6979 and
|
||||
// BIP0062, optimized specifically for the secp256k1 curve using the Elliptic Curve
|
||||
// Digital Signature Algorithm (ECDSA), as defined in FIPS 186-3. See
|
||||
// https://www.secg.org/sec2-v2.pdf for details on the secp256k1 standard.
|
||||
//
|
||||
// It also provides functions to parse and serialize the ECDSA signatures with the
|
||||
// more strict Distinguished Encoding Rules (DER) of ISO/IEC 8825-1 and some
|
||||
// additional restrictions specific to secp256k1.
|
||||
//
|
||||
// In addition, it supports a custom "compact" signature format which allows
|
||||
// efficient recovery of the public key from a given valid signature and message
|
||||
// hash combination.
|
||||
//
|
||||
// A comprehensive suite of tests is provided to ensure proper functionality.
|
||||
//
|
||||
// # ECDSA use in Decred
|
||||
//
|
||||
// At the time of this writing, ECDSA signatures are heavily used for proving coin
|
||||
// ownership in Decred as the vast majority of transactions consist of what is
|
||||
// effectively transferring ownership of coins to a public key associated with a
|
||||
// secret key only known to the recipient of the coins along with an encumbrance
|
||||
// that requires an ECDSA signature that proves the new owner possesses the secret
|
||||
// key without actually revealing it.
|
||||
//
|
||||
// # Errors
|
||||
//
|
||||
// The errors returned by this package are of type ecdsa.Error and fully support
|
||||
// the standard library errors.Is and errors.As functions. This allows the caller
|
||||
// to programmatically determine the specific error by examining the ErrorKind
|
||||
// field of the type asserted ecdsa.Error while still providing rich error messages
|
||||
// with contextual information. See ErrorKind in the package documentation for a
|
||||
// full list.
|
||||
package ecdsa |
||||
@ -1,106 +0,0 @@
@@ -1,106 +0,0 @@
|
||||
// Copyright (c) 2020-2022 The Decred developers
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package ecdsa |
||||
|
||||
// ErrorKind identifies a kind of error. It has full support for
|
||||
// errors.Is and errors.As, so the caller can directly check against
|
||||
// an error kind when determining the reason for an error.
|
||||
type ErrorKind string |
||||
|
||||
// These constants are used to identify a specific Error.
|
||||
const ( |
||||
// ErrSigTooShort is returned when a signature that should be a DER
|
||||
// signature is too short.
|
||||
ErrSigTooShort = ErrorKind("ErrSigTooShort") |
||||
// ErrSigTooLong is returned when a signature that should be a DER signature
|
||||
// is too long.
|
||||
ErrSigTooLong = ErrorKind("ErrSigTooLong") |
||||
// ErrSigInvalidSeqID is returned when a signature that should be a DER
|
||||
// signature does not have the expected ASN.1 sequence ID.
|
||||
ErrSigInvalidSeqID = ErrorKind("ErrSigInvalidSeqID") |
||||
// ErrSigInvalidDataLen is returned when a signature that should be a DER
|
||||
// signature does not specify the correct number of remaining bytes for the
|
||||
// R and S portions.
|
||||
ErrSigInvalidDataLen = ErrorKind("ErrSigInvalidDataLen") |
||||
// ErrSigMissingSTypeID is returned when a signature that should be a DER
|
||||
// signature does not provide the ASN.1 type ID for S.
|
||||
ErrSigMissingSTypeID = ErrorKind("ErrSigMissingSTypeID") |
||||
// ErrSigMissingSLen is returned when a signature that should be a DER
|
||||
// signature does not provide the length of S.
|
||||
ErrSigMissingSLen = ErrorKind("ErrSigMissingSLen") |
||||
// ErrSigInvalidSLen is returned when a signature that should be a DER
|
||||
// signature does not specify the correct number of bytes for the S portion.
|
||||
ErrSigInvalidSLen = ErrorKind("ErrSigInvalidSLen") |
||||
// ErrSigInvalidRIntID is returned when a signature that should be a DER
|
||||
// signature does not have the expected ASN.1 integer ID for R.
|
||||
ErrSigInvalidRIntID = ErrorKind("ErrSigInvalidRIntID") |
||||
// ErrSigZeroRLen is returned when a signature that should be a DER
|
||||
// signature has an R length of zero.
|
||||
ErrSigZeroRLen = ErrorKind("ErrSigZeroRLen") |
||||
// ErrSigNegativeR is returned when a signature that should be a DER
|
||||
// signature has a negative value for R.
|
||||
ErrSigNegativeR = ErrorKind("ErrSigNegativeR") |
||||
// ErrSigTooMuchRPadding is returned when a signature that should be a DER
|
||||
// signature has too much padding for R.
|
||||
ErrSigTooMuchRPadding = ErrorKind("ErrSigTooMuchRPadding") |
||||
// ErrSigRIsZero is returned when a signature has R set to the value zero.
|
||||
ErrSigRIsZero = ErrorKind("ErrSigRIsZero") |
||||
// ErrSigRTooBig is returned when a signature has R with a value that is
|
||||
// greater than or equal to the group order.
|
||||
ErrSigRTooBig = ErrorKind("ErrSigRTooBig") |
||||
// ErrSigInvalidSIntID is returned when a signature that should be a DER
|
||||
// signature does not have the expected ASN.1 integer ID for S.
|
||||
ErrSigInvalidSIntID = ErrorKind("ErrSigInvalidSIntID") |
||||
// ErrSigZeroSLen is returned when a signature that should be a DER
|
||||
// signature has an S length of zero.
|
||||
ErrSigZeroSLen = ErrorKind("ErrSigZeroSLen") |
||||
// ErrSigNegativeS is returned when a signature that should be a DER
|
||||
// signature has a negative value for S.
|
||||
ErrSigNegativeS = ErrorKind("ErrSigNegativeS") |
||||
// ErrSigTooMuchSPadding is returned when a signature that should be a DER
|
||||
// signature has too much padding for S.
|
||||
ErrSigTooMuchSPadding = ErrorKind("ErrSigTooMuchSPadding") |
||||
// ErrSigSIsZero is returned when a signature has S set to the value zero.
|
||||
ErrSigSIsZero = ErrorKind("ErrSigSIsZero") |
||||
// ErrSigSTooBig is returned when a signature has S with a value that is
|
||||
// greater than or equal to the group order.
|
||||
ErrSigSTooBig = ErrorKind("ErrSigSTooBig") |
||||
// ErrSigInvalidLen is returned when a signature that should be a compact
|
||||
// signature is not the required length.
|
||||
ErrSigInvalidLen = ErrorKind("ErrSigInvalidLen") |
||||
// ErrSigInvalidRecoveryCode is returned when a signature that should be a
|
||||
// compact signature has an invalid value for the public key recovery code.
|
||||
ErrSigInvalidRecoveryCode = ErrorKind("ErrSigInvalidRecoveryCode") |
||||
// ErrSigOverflowsPrime is returned when a signature that should be a
|
||||
// compact signature has the overflow bit set but adding the order to it
|
||||
// would overflow the underlying field prime.
|
||||
ErrSigOverflowsPrime = ErrorKind("ErrSigOverflowsPrime") |
||||
// ErrPointNotOnCurve is returned when attempting to recover a public key
|
||||
// from a compact signature results in a point that is not on the elliptic
|
||||
// curve.
|
||||
ErrPointNotOnCurve = ErrorKind("ErrPointNotOnCurve") |
||||
) |
||||
|
||||
// Error satisfies the error interface and prints human-readable errors.
|
||||
func (e ErrorKind) Error() string { return string(e) } |
||||
|
||||
// Error identifies an error related to an ECDSA signature. It has full
|
||||
// support for errors.Is and errors.As, so the caller can ascertain the
|
||||
// specific reason for the error by checking the underlying error.
|
||||
type Error struct { |
||||
Err error |
||||
Description string |
||||
} |
||||
|
||||
// Error satisfies the error interface and prints human-readable errors.
|
||||
func (e Error) Error() string { return e.Description } |
||||
|
||||
// Unwrap returns the underlying wrapped error.
|
||||
func (e Error) Unwrap() error { return e.Err } |
||||
|
||||
// signatureError creates an Error given a set of arguments.
|
||||
func signatureError(kind ErrorKind, desc string) Error { |
||||
return Error{Err: kind, Description: desc} |
||||
} |
||||
@ -1,154 +0,0 @@
@@ -1,154 +0,0 @@
|
||||
// Copyright (c) 2020-2022 The Decred developers
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package ecdsa |
||||
|
||||
import ( |
||||
"errors" |
||||
"testing" |
||||
) |
||||
|
||||
// TestErrorKindStringer tests the stringized output for the ErrorKind type.
|
||||
func TestErrorKindStringer(t *testing.T) { |
||||
tests := []struct { |
||||
in ErrorKind |
||||
want string |
||||
}{ |
||||
{ErrSigTooShort, "ErrSigTooShort"}, |
||||
{ErrSigTooLong, "ErrSigTooLong"}, |
||||
{ErrSigInvalidSeqID, "ErrSigInvalidSeqID"}, |
||||
{ErrSigInvalidDataLen, "ErrSigInvalidDataLen"}, |
||||
{ErrSigMissingSTypeID, "ErrSigMissingSTypeID"}, |
||||
{ErrSigMissingSLen, "ErrSigMissingSLen"}, |
||||
{ErrSigInvalidSLen, "ErrSigInvalidSLen"}, |
||||
{ErrSigInvalidRIntID, "ErrSigInvalidRIntID"}, |
||||
{ErrSigZeroRLen, "ErrSigZeroRLen"}, |
||||
{ErrSigNegativeR, "ErrSigNegativeR"}, |
||||
{ErrSigTooMuchRPadding, "ErrSigTooMuchRPadding"}, |
||||
{ErrSigRIsZero, "ErrSigRIsZero"}, |
||||
{ErrSigRTooBig, "ErrSigRTooBig"}, |
||||
{ErrSigInvalidSIntID, "ErrSigInvalidSIntID"}, |
||||
{ErrSigZeroSLen, "ErrSigZeroSLen"}, |
||||
{ErrSigNegativeS, "ErrSigNegativeS"}, |
||||
{ErrSigTooMuchSPadding, "ErrSigTooMuchSPadding"}, |
||||
{ErrSigSIsZero, "ErrSigSIsZero"}, |
||||
{ErrSigSTooBig, "ErrSigSTooBig"}, |
||||
{ErrSigInvalidLen, "ErrSigInvalidLen"}, |
||||
{ErrSigInvalidRecoveryCode, "ErrSigInvalidRecoveryCode"}, |
||||
{ErrSigOverflowsPrime, "ErrSigOverflowsPrime"}, |
||||
{ErrPointNotOnCurve, "ErrPointNotOnCurve"}, |
||||
} |
||||
|
||||
for i, test := range tests { |
||||
result := test.in.Error() |
||||
if result != test.want { |
||||
t.Errorf("#%d: got: %s want: %s", i, result, test.want) |
||||
continue |
||||
} |
||||
} |
||||
} |
||||
|
||||
// TestError tests the error output for the Error type.
|
||||
func TestError(t *testing.T) { |
||||
tests := []struct { |
||||
in Error |
||||
want string |
||||
}{ |
||||
{ |
||||
Error{Description: "some error"}, |
||||
"some error", |
||||
}, { |
||||
Error{Description: "human-readable error"}, |
||||
"human-readable error", |
||||
}, |
||||
} |
||||
for i, test := range tests { |
||||
result := test.in.Error() |
||||
if result != test.want { |
||||
t.Errorf("#%d: got: %s want: %s", i, result, test.want) |
||||
continue |
||||
} |
||||
} |
||||
} |
||||
|
||||
// TestErrorKindIsAs ensures both ErrorKind and Error can be identified as being
|
||||
// a specific error kind via errors.Is and unwrapped via errors.As.
|
||||
func TestErrorKindIsAs(t *testing.T) { |
||||
tests := []struct { |
||||
name string |
||||
err error |
||||
target error |
||||
wantMatch bool |
||||
wantAs ErrorKind |
||||
}{ |
||||
{ |
||||
name: "ErrSigTooShort == ErrSigTooShort", |
||||
err: ErrSigTooShort, |
||||
target: ErrSigTooShort, |
||||
wantMatch: true, |
||||
wantAs: ErrSigTooShort, |
||||
}, { |
||||
name: "Error.ErrSigTooShort == ErrSigTooShort", |
||||
err: signatureError(ErrSigTooShort, ""), |
||||
target: ErrSigTooShort, |
||||
wantMatch: true, |
||||
wantAs: ErrSigTooShort, |
||||
}, { |
||||
name: "Error.ErrSigTooShort == Error.ErrSigTooShort", |
||||
err: signatureError(ErrSigTooShort, ""), |
||||
target: signatureError(ErrSigTooShort, ""), |
||||
wantMatch: true, |
||||
wantAs: ErrSigTooShort, |
||||
}, { |
||||
name: "ErrSigTooLong != ErrSigTooShort", |
||||
err: ErrSigTooLong, |
||||
target: ErrSigTooShort, |
||||
wantMatch: false, |
||||
wantAs: ErrSigTooLong, |
||||
}, { |
||||
name: "Error.ErrSigTooLong != ErrSigTooShort", |
||||
err: signatureError(ErrSigTooLong, ""), |
||||
target: ErrSigTooShort, |
||||
wantMatch: false, |
||||
wantAs: ErrSigTooLong, |
||||
}, { |
||||
name: "ErrSigTooLong != Error.ErrSigTooShort", |
||||
err: ErrSigTooLong, |
||||
target: signatureError(ErrSigTooShort, ""), |
||||
wantMatch: false, |
||||
wantAs: ErrSigTooLong, |
||||
}, { |
||||
name: "Error.ErrSigTooLong != Error.ErrSigTooShort", |
||||
err: signatureError(ErrSigTooLong, ""), |
||||
target: signatureError(ErrSigTooShort, ""), |
||||
wantMatch: false, |
||||
wantAs: ErrSigTooLong, |
||||
}, |
||||
} |
||||
for _, test := range tests { |
||||
// Ensure the error matches or not depending on the expected result.
|
||||
result := errors.Is(test.err, test.target) |
||||
if result != test.wantMatch { |
||||
t.Errorf( |
||||
"%s: incorrect error identification -- got %v, want %v", |
||||
test.name, result, test.wantMatch, |
||||
) |
||||
continue |
||||
} |
||||
// Ensure the underlying error kind can be unwrapped and is the
|
||||
// expected code.
|
||||
var kind ErrorKind |
||||
if !errors.As(test.err, &kind) { |
||||
t.Errorf("%s: unable to unwrap to error", test.name) |
||||
continue |
||||
} |
||||
if !errors.Is(kind, test.wantAs) { |
||||
t.Errorf( |
||||
"%s: unexpected unwrapped error -- got %v, want %v", |
||||
test.name, kind, test.wantAs, |
||||
) |
||||
continue |
||||
} |
||||
} |
||||
} |
||||
@ -1,79 +0,0 @@
@@ -1,79 +0,0 @@
|
||||
// Copyright (c) 2014 The btcsuite developers
|
||||
// Copyright (c) 2015-2021 The Decred developers
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// TODO: change this to work with sha256
|
||||
|
||||
package ecdsa_test |
||||
|
||||
// // This example demonstrates signing a message with a secp256k1 secret key that
|
||||
// // is first parsed from raw bytes and serializing the generated signature.
|
||||
// func ExampleSign() {
|
||||
// // Decode a hex-encoded secret key.
|
||||
// pkBytes, err := hex.Dec("22a47fa09a223f2aa079edf85a7c2d4f87" +
|
||||
// "20ee63e502ee2869afab7de234b80c")
|
||||
// if err != nil {
|
||||
// fmt.Println(err)
|
||||
// return
|
||||
// }
|
||||
// secKey := secp256k1.SecKeyFromBytes(pkBytes)
|
||||
//
|
||||
// // Sign a message using the secret key.
|
||||
// message := "test message"
|
||||
// messageHash := blake256.Sum256(by(message))
|
||||
// signature := ecdsa.Sign(secKey, messageHash[:])
|
||||
//
|
||||
// // Serialize and display the signature.
|
||||
// fmt.Printf("Serialized Signature: %x\n", signature.Serialize())
|
||||
//
|
||||
// // Verify the signature for the message using the public key.
|
||||
// pubKey := secKey.Pubkey()
|
||||
// verified := signature.Verify(messageHash[:], pubKey)
|
||||
// fmt.Printf("Signature Verified? %v\n", verified)
|
||||
//
|
||||
// // Output:
|
||||
// // Serialized Signature: 3045022100fcc0a8768cfbcefcf2cadd7cfb0fb18ed08dd2e2ae84bef1a474a3d351b26f0302200fc1a350b45f46fa00101391302818d748c2b22615511a3ffd5bb638bd777207
|
||||
// // Signature Verified? true
|
||||
// }
|
||||
|
||||
// // This example demonstrates verifying a secp256k1 signature against a public
|
||||
// // key that is first parsed from raw bytes. The signature is also parsed from
|
||||
// // raw bytes.
|
||||
// func ExampleSignature_Verify() {
|
||||
// // Decode hex-encoded serialized public key.
|
||||
// pubKeyBytes, err := hex.Dec("02a673638cb9587cb68ea08dbef685c" +
|
||||
// "6f2d2a751a8b3c6f2a7e9a4999e6e4bfaf5")
|
||||
// if err != nil {
|
||||
// fmt.Println(err)
|
||||
// return
|
||||
// }
|
||||
// pubKey, err := secp256k1.ParsePubKey(pubKeyBytes)
|
||||
// if err != nil {
|
||||
// fmt.Println(err)
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// // Decode hex-encoded serialized signature.
|
||||
// sigBytes, err := hex.Dec("3045022100fcc0a8768cfbcefcf2cadd7cfb0" +
|
||||
// "fb18ed08dd2e2ae84bef1a474a3d351b26f0302200fc1a350b45f46fa0010139130" +
|
||||
// "2818d748c2b22615511a3ffd5bb638bd777207")
|
||||
// if err != nil {
|
||||
// fmt.Println(err)
|
||||
// return
|
||||
// }
|
||||
// signature, err := ecdsa.ParseDERSignature(sigBytes)
|
||||
// if err != nil {
|
||||
// fmt.Println(err)
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// // Verify the signature for the message using the public key.
|
||||
// message := "test message"
|
||||
// messageHash := blake256.Sum256(by(message))
|
||||
// verified := signature.Verify(messageHash[:], pubKey)
|
||||
// fmt.Println("Signature Verified?", verified)
|
||||
//
|
||||
// // Output:
|
||||
// // Signature Verified? true
|
||||
// }
|
||||
@ -1,954 +0,0 @@
@@ -1,954 +0,0 @@
|
||||
// Copyright (c) 2013-2014 The btcsuite developers
|
||||
// Copyright (c) 2015-2022 The Decred developers
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package ecdsa |
||||
|
||||
import ( |
||||
"fmt" |
||||
|
||||
"next.orly.dev/pkg/crypto/ec/secp256k1" |
||||
) |
||||
|
||||
// References:
|
||||
// [GECC]: Guide to Elliptic Curve Cryptography (Hankerson, Menezes, Vanstone)
|
||||
//
|
||||
// [ISO/IEC 8825-1]: Information technology — ASN.1 encoding rules:
|
||||
// Specification of Basic Encoding Rules (BER), Canonical Encoding Rules
|
||||
// (CER) and Distinguished Encoding Rules (DER)
|
||||
//
|
||||
// [SEC1]: Elliptic Curve Cryptography (May 31, 2009, Version 2.0)
|
||||
// https://www.secg.org/sec1-v2.pdf
|
||||
|
||||
var ( |
||||
// zero32 is an array of 32 bytes used for the purposes of zeroing and is
|
||||
// defined here to avoid extra allocations.
|
||||
zero32 = [32]byte{} |
||||
// orderAsFieldVal is the order of the secp256k1 curve group stored as a
|
||||
// field value. It is provided here to avoid the need to create it multiple
|
||||
// times.
|
||||
orderAsFieldVal = func() secp256k1.FieldVal { |
||||
var f secp256k1.FieldVal |
||||
f.SetByteSlice(secp256k1.Params().N.Bytes()) |
||||
return f |
||||
}() |
||||
) |
||||
|
||||
const ( |
||||
// asn1SequenceID is the ASN.1 identifier for a sequence and is used when
|
||||
// parsing and serializing signatures encoded with the Distinguished
|
||||
// Encoding Rules (DER) format per section 10 of [ISO/IEC 8825-1].
|
||||
asn1SequenceID = 0x30 |
||||
// asn1IntegerID is the ASN.1 identifier for an integer and is used when
|
||||
// parsing and serializing signatures encoded with the Distinguished
|
||||
// Encoding Rules (DER) format per section 10 of [ISO/IEC 8825-1].
|
||||
asn1IntegerID = 0x02 |
||||
) |
||||
|
||||
// Signature is a type representing an ECDSA signature.
|
||||
type Signature struct { |
||||
r secp256k1.ModNScalar |
||||
s secp256k1.ModNScalar |
||||
} |
||||
|
||||
// NewSignature instantiates a new signature given some r and s values.
|
||||
func NewSignature(r, s *secp256k1.ModNScalar) *Signature { |
||||
return &Signature{*r, *s} |
||||
} |
||||
|
||||
// Serialize returns the ECDSA signature in the Distinguished Encoding Rules
|
||||
// (DER) format per section 10 of [ISO/IEC 8825-1] and such that the S component
|
||||
// of the signature is less than or equal to the half order of the group.
|
||||
//
|
||||
// Note that the serialized bytes returned do not include the appended hash type
|
||||
// used in Decred signature scripts.
|
||||
func (sig *Signature) Serialize() []byte { |
||||
// The format of a DER encoded signature is as follows:
|
||||
//
|
||||
// 0x30 <total length> 0x02 <length of R> <R> 0x02 <length of S> <S>
|
||||
// - 0x30 is the ASN.1 identifier for a sequence.
|
||||
// - Total length is 1 byte and specifies length of all remaining data.
|
||||
// - 0x02 is the ASN.1 identifier that specifies an integer follows.
|
||||
// - Length of R is 1 byte and specifies how many bytes R occupies.
|
||||
// - R is the arbitrary length big-endian encoded number which
|
||||
// represents the R value of the signature. DER encoding dictates
|
||||
// that the value must be encoded using the minimum possible number
|
||||
// of bytes. This implies the first byte can only be null if the
|
||||
// highest bit of the next byte is set in order to prevent it from
|
||||
// being interpreted as a negative number.
|
||||
// - 0x02 is once again the ASN.1 integer identifier.
|
||||
// - Length of S is 1 byte and specifies how many bytes S occupies.
|
||||
// - S is the arbitrary length big-endian encoded number which
|
||||
// represents the S value of the signature. The encoding rules are
|
||||
// identical as those for R.
|
||||
|
||||
// Ensure the S component of the signature is less than or equal to the half
|
||||
// order of the group because both S and its negation are valid signatures
|
||||
// modulo the order, so this forces a consistent choice to reduce signature
|
||||
// malleability.
|
||||
sigS := new(secp256k1.ModNScalar).Set(&sig.s) |
||||
if sigS.IsOverHalfOrder() { |
||||
sigS.Negate() |
||||
} |
||||
|
||||
// Serialize the R and S components of the signature into their fixed
|
||||
// 32-byte big-endian encoding. Note that the extra leading zero byte is
|
||||
// used to ensure it is canonical per DER and will be stripped if needed
|
||||
// below.
|
||||
var rBuf, sBuf [33]byte |
||||
sig.r.PutBytesUnchecked(rBuf[1:33]) |
||||
sigS.PutBytesUnchecked(sBuf[1:33]) |
||||
// Ensure the encoded bytes for the R and S components are canonical per DER
|
||||
// by trimming all leading zero bytes so long as the next byte does not have
|
||||
// the high bit set and it's not the final byte.
|
||||
canonR, canonS := rBuf[:], sBuf[:] |
||||
for len(canonR) > 1 && canonR[0] == 0x00 && canonR[1]&0x80 == 0 { |
||||
canonR = canonR[1:] |
||||
} |
||||
for len(canonS) > 1 && canonS[0] == 0x00 && canonS[1]&0x80 == 0 { |
||||
canonS = canonS[1:] |
||||
} |
||||
// Total length of returned signature is 1 byte for each magic and length
|
||||
// (6 total), plus lengths of R and S.
|
||||
totalLen := 6 + len(canonR) + len(canonS) |
||||
b := make([]byte, 0, totalLen) |
||||
b = append(b, asn1SequenceID) |
||||
b = append(b, byte(totalLen-2)) |
||||
b = append(b, asn1IntegerID) |
||||
b = append(b, byte(len(canonR))) |
||||
b = append(b, canonR...) |
||||
b = append(b, asn1IntegerID) |
||||
b = append(b, byte(len(canonS))) |
||||
b = append(b, canonS...) |
||||
return b |
||||
} |
||||
|
||||
// zeroArray32 zeroes the provided 32-byte buffer.
|
||||
func zeroArray32(b *[32]byte) { |
||||
copy(b[:], zero32[:]) |
||||
} |
||||
|
||||
// fieldToModNScalar converts a field value to scalar modulo the group order and
|
||||
// returns the scalar along with either 1 if it was reduced (aka it overflowed)
|
||||
// or 0 otherwise.
|
||||
//
|
||||
// Note that a bool is not used here because it is not possible in Go to convert
|
||||
// from a bool to numeric value in constant time and many constant-time
|
||||
// operations require a numeric value.
|
||||
func fieldToModNScalar(v *secp256k1.FieldVal) (secp256k1.ModNScalar, uint32) { |
||||
var buf [32]byte |
||||
v.PutBytes(&buf) |
||||
var s secp256k1.ModNScalar |
||||
overflow := s.SetBytes(&buf) |
||||
zeroArray32(&buf) |
||||
return s, overflow |
||||
} |
||||
|
||||
// modNScalarToField converts a scalar modulo the group order to a field value.
|
||||
func modNScalarToField(v *secp256k1.ModNScalar) secp256k1.FieldVal { |
||||
var buf [32]byte |
||||
v.PutBytes(&buf) |
||||
var fv secp256k1.FieldVal |
||||
fv.SetBytes(&buf) |
||||
return fv |
||||
} |
||||
|
||||
// Verify returns whether the signature is valid for the provided hash
|
||||
// and secp256k1 public key.
|
||||
func (sig *Signature) Verify(hash []byte, pubKey *secp256k1.PublicKey) bool { |
||||
// The algorithm for verifying an ECDSA signature is given as algorithm 4.30
|
||||
// in [GECC].
|
||||
//
|
||||
// The following is a paraphrased version for reference:
|
||||
//
|
||||
// G = curve generator
|
||||
// N = curve order
|
||||
// Q = public key
|
||||
// m = message
|
||||
// R, S = signature
|
||||
//
|
||||
// 1. Fail if R and S are not in [1, N-1]
|
||||
// 2. e = H(m)
|
||||
// 3. w = S^-1 mod N
|
||||
// 4. u1 = e * w mod N
|
||||
// u2 = R * w mod N
|
||||
// 5. X = u1G + u2Q
|
||||
// 6. Fail if X is the point at infinity
|
||||
// 7. x = X.x mod N (X.x is the x coordinate of X)
|
||||
// 8. Verified if x == R
|
||||
//
|
||||
// However, since all group operations are done internally in Jacobian
|
||||
// projective space, the algorithm is modified slightly here in order to
|
||||
// avoid an expensive inversion back into affine coordinates at step 7.
|
||||
// Credits to Greg Maxwell for originally suggesting this optimization.
|
||||
//
|
||||
// Ordinarily, step 7 involves converting the x coordinate to affine by
|
||||
// calculating x = x / z^2 (mod P) and then calculating the remainder as
|
||||
// x = x (mod N). Then step 8 compares it to R.
|
||||
//
|
||||
// Note that since R is the x coordinate mod N from a random point that was
|
||||
// originally mod P, and the cofactor of the secp256k1 curve is 1, there are
|
||||
// only two possible x coordinates that the original random point could have
|
||||
// been to produce R: x, where x < N, and x+N, where x+N < P.
|
||||
//
|
||||
// This implies that the signature is valid if either:
|
||||
// a) R == X.x / X.z^2 (mod P)
|
||||
// => R * X.z^2 == X.x (mod P)
|
||||
// --or--
|
||||
// b) R + N < P && R + N == X.x / X.z^2 (mod P)
|
||||
// => R + N < P && (R + N) * X.z^2 == X.x (mod P)
|
||||
//
|
||||
// Therefore the following modified algorithm is used:
|
||||
//
|
||||
// 1. Fail if R and S are not in [1, N-1]
|
||||
// 2. e = H(m)
|
||||
// 3. w = S^-1 mod N
|
||||
// 4. u1 = e * w mod N
|
||||
// u2 = R * w mod N
|
||||
// 5. X = u1G + u2Q
|
||||
// 6. Fail if X is the point at infinity
|
||||
// 7. z = (X.z)^2 mod P (X.z is the z coordinate of X)
|
||||
// 8. Verified if R * z == X.x (mod P)
|
||||
// 9. Fail if R + N >= P
|
||||
// 10. Verified if (R + N) * z == X.x (mod P)
|
||||
//
|
||||
// Step 1.
|
||||
//
|
||||
// Fail if R and S are not in [1, N-1].
|
||||
if sig.r.IsZero() || sig.s.IsZero() { |
||||
return false |
||||
} |
||||
// Step 2.
|
||||
//
|
||||
// e = H(m)
|
||||
var e secp256k1.ModNScalar |
||||
e.SetByteSlice(hash) |
||||
// Step 3.
|
||||
//
|
||||
// w = S^-1 mod N
|
||||
w := new(secp256k1.ModNScalar).InverseValNonConst(&sig.s) |
||||
// Step 4.
|
||||
//
|
||||
// u1 = e * w mod N
|
||||
// u2 = R * w mod N
|
||||
u1 := new(secp256k1.ModNScalar).Mul2(&e, w) |
||||
u2 := new(secp256k1.ModNScalar).Mul2(&sig.r, w) |
||||
// Step 5.
|
||||
//
|
||||
// X = u1G + u2Q
|
||||
var X, Q, u1G, u2Q secp256k1.JacobianPoint |
||||
pubKey.AsJacobian(&Q) |
||||
secp256k1.ScalarBaseMultNonConst(u1, &u1G) |
||||
secp256k1.ScalarMultNonConst(u2, &Q, &u2Q) |
||||
secp256k1.AddNonConst(&u1G, &u2Q, &X) |
||||
// Step 6.
|
||||
//
|
||||
// Fail if X is the point at infinity
|
||||
if (X.X.IsZero() && X.Y.IsZero()) || X.Z.IsZero() { |
||||
return false |
||||
} |
||||
// Step 7.
|
||||
//
|
||||
// z = (X.z)^2 mod P (X.z is the z coordinate of X)
|
||||
z := new(secp256k1.FieldVal).SquareVal(&X.Z) |
||||
// Step 8.
|
||||
//
|
||||
// Verified if R * z == X.x (mod P)
|
||||
sigRModP := modNScalarToField(&sig.r) |
||||
result := new(secp256k1.FieldVal).Mul2(&sigRModP, z).Normalize() |
||||
if result.Equals(&X.X) { |
||||
return true |
||||
} |
||||
// Step 9.
|
||||
//
|
||||
// Fail if R + N >= P
|
||||
if sigRModP.IsGtOrEqPrimeMinusOrder() { |
||||
return false |
||||
} |
||||
// Step 10.
|
||||
//
|
||||
// Verified if (R + N) * z == X.x (mod P)
|
||||
sigRModP.Add(&orderAsFieldVal) |
||||
result.Mul2(&sigRModP, z).Normalize() |
||||
return result.Equals(&X.X) |
||||
} |
||||
|
||||
// IsEqual compares this Signature instance to the one passed, returning true if
|
||||
// both Signatures are equivalent. A signature is equivalent to another, if
|
||||
// they both have the same scalar value for R and S.
|
||||
func (sig *Signature) IsEqual(otherSig *Signature) bool { |
||||
return sig.r.Equals(&otherSig.r) && sig.s.Equals(&otherSig.s) |
||||
} |
||||
|
||||
// ParseDERSignature parses a signature in the Distinguished Encoding Rules
|
||||
// (DER) format per section 10 of [ISO/IEC 8825-1] and enforces the following
|
||||
// additional restrictions specific to secp256k1:
|
||||
//
|
||||
// - The R and S values must be in the valid range for secp256k1 scalars:
|
||||
// - Negative values are rejected
|
||||
// - Zero is rejected
|
||||
// - Values greater than or equal to the secp256k1 group order are rejected
|
||||
func ParseDERSignature(sig []byte) (*Signature, error) { |
||||
// The format of a DER encoded signature for secp256k1 is as follows:
|
||||
//
|
||||
// 0x30 <total length> 0x02 <length of R> <R> 0x02 <length of S> <S>
|
||||
// - 0x30 is the ASN.1 identifier for a sequence
|
||||
// - Total length is 1 byte and specifies length of all remaining data
|
||||
// - 0x02 is the ASN.1 identifier that specifies an integer follows
|
||||
// - Length of R is 1 byte and specifies how many bytes R occupies
|
||||
// - R is the arbitrary length big-endian encoded number which
|
||||
// represents the R value of the signature. DER encoding dictates
|
||||
// that the value must be encoded using the minimum possible number
|
||||
// of bytes. This implies the first byte can only be null if the
|
||||
// highest bit of the next byte is set in order to prevent it from
|
||||
// being interpreted as a negative number.
|
||||
// - 0x02 is once again the ASN.1 integer identifier
|
||||
// - Length of S is 1 byte and specifies how many bytes S occupies
|
||||
// - S is the arbitrary length big-endian encoded number which
|
||||
// represents the S value of the signature. The encoding rules are
|
||||
// identical as those for R.
|
||||
//
|
||||
// NOTE: The DER specification supports specifying lengths that can occupy
|
||||
// more than 1 byte, however, since this is specific to secp256k1
|
||||
// signatures, all lengths will be a single byte.
|
||||
const ( |
||||
// minSigLen is the minimum length of a DER encoded signature and is
|
||||
// when both R and S are 1 byte each.
|
||||
//
|
||||
// 0x30 + <1-byte> + 0x02 + 0x01 + <byte> + 0x2 + 0x01 + <byte>
|
||||
minSigLen = 8 |
||||
// maxSigLen is the maximum length of a DER encoded signature and is
|
||||
// when both R and S are 33 bytes each. It is 33 bytes because a
|
||||
// 256-bit integer requires 32 bytes and an additional leading null byte
|
||||
// might be required if the high bit is set in the value.
|
||||
//
|
||||
// 0x30 + <1-byte> + 0x02 + 0x21 + <33 bytes> + 0x2 + 0x21 + <33 bytes>
|
||||
maxSigLen = 72 |
||||
// sequenceOffset is the byte offset within the signature of the
|
||||
// expected ASN.1 sequence identifier.
|
||||
sequenceOffset = 0 |
||||
// dataLenOffset is the byte offset within the signature of the expected
|
||||
// total length of all remaining data in the signature.
|
||||
dataLenOffset = 1 |
||||
// rTypeOffset is the byte offset within the signature of the ASN.1
|
||||
// identifier for R and is expected to indicate an ASN.1 integer.
|
||||
rTypeOffset = 2 |
||||
// rLenOffset is the byte offset within the signature of the length of
|
||||
// R.
|
||||
rLenOffset = 3 |
||||
// rOffset is the byte offset within the signature of R.
|
||||
rOffset = 4 |
||||
) |
||||
// The signature must adhere to the minimum and maximum allowed length.
|
||||
sigLen := len(sig) |
||||
if sigLen < minSigLen { |
||||
str := fmt.Sprintf( |
||||
"malformed signature: too short: %d < %d", sigLen, |
||||
minSigLen, |
||||
) |
||||
return nil, signatureError(ErrSigTooShort, str) |
||||
} |
||||
if sigLen > maxSigLen { |
||||
str := fmt.Sprintf( |
||||
"malformed signature: too long: %d > %d", sigLen, |
||||
maxSigLen, |
||||
) |
||||
return nil, signatureError(ErrSigTooLong, str) |
||||
} |
||||
// The signature must start with the ASN.1 sequence identifier.
|
||||
if sig[sequenceOffset] != asn1SequenceID { |
||||
str := fmt.Sprintf( |
||||
"malformed signature: format has wrong type: %#x", |
||||
sig[sequenceOffset], |
||||
) |
||||
return nil, signatureError(ErrSigInvalidSeqID, str) |
||||
} |
||||
// The signature must indicate the correct amount of data for all elements
|
||||
// related to R and S.
|
||||
if int(sig[dataLenOffset]) != sigLen-2 { |
||||
str := fmt.Sprintf( |
||||
"malformed signature: bad length: %d != %d", |
||||
sig[dataLenOffset], sigLen-2, |
||||
) |
||||
return nil, signatureError(ErrSigInvalidDataLen, str) |
||||
} |
||||
// Calculate the offsets of the elements related to S and ensure S is inside
|
||||
// the signature.
|
||||
//
|
||||
// rLen specifies the length of the big-endian encoded number which
|
||||
// represents the R value of the signature.
|
||||
//
|
||||
// sTypeOffset is the offset of the ASN.1 identifier for S and, like its R
|
||||
// counterpart, is expected to indicate an ASN.1 integer.
|
||||
//
|
||||
// sLenOffset and sOffset are the byte offsets within the signature of the
|
||||
// length of S and S itself, respectively.
|
||||
rLen := int(sig[rLenOffset]) |
||||
sTypeOffset := rOffset + rLen |
||||
sLenOffset := sTypeOffset + 1 |
||||
if sTypeOffset >= sigLen { |
||||
str := "malformed signature: S type indicator missing" |
||||
return nil, signatureError(ErrSigMissingSTypeID, str) |
||||
} |
||||
if sLenOffset >= sigLen { |
||||
str := "malformed signature: S length missing" |
||||
return nil, signatureError(ErrSigMissingSLen, str) |
||||
} |
||||
// The lengths of R and S must match the overall length of the signature.
|
||||
//
|
||||
// sLen specifies the length of the big-endian encoded number which
|
||||
// represents the S value of the signature.
|
||||
sOffset := sLenOffset + 1 |
||||
sLen := int(sig[sLenOffset]) |
||||
if sOffset+sLen != sigLen { |
||||
str := "malformed signature: invalid S length" |
||||
return nil, signatureError(ErrSigInvalidSLen, str) |
||||
} |
||||
// R elements must be ASN.1 integers.
|
||||
if sig[rTypeOffset] != asn1IntegerID { |
||||
str := fmt.Sprintf( |
||||
"malformed signature: R integer marker: %#x != %#x", |
||||
sig[rTypeOffset], asn1IntegerID, |
||||
) |
||||
return nil, signatureError(ErrSigInvalidRIntID, str) |
||||
} |
||||
// Zero-length integers are not allowed for R.
|
||||
if rLen == 0 { |
||||
str := "malformed signature: R length is zero" |
||||
return nil, signatureError(ErrSigZeroRLen, str) |
||||
} |
||||
// R must not be negative.
|
||||
if sig[rOffset]&0x80 != 0 { |
||||
str := "malformed signature: R is negative" |
||||
return nil, signatureError(ErrSigNegativeR, str) |
||||
} |
||||
// Null bytes at the start of R are not allowed, unless R would otherwise be
|
||||
// interpreted as a negative number.
|
||||
if rLen > 1 && sig[rOffset] == 0x00 && sig[rOffset+1]&0x80 == 0 { |
||||
str := "malformed signature: R value has too much padding" |
||||
return nil, signatureError(ErrSigTooMuchRPadding, str) |
||||
} |
||||
// S elements must be ASN.1 integers.
|
||||
if sig[sTypeOffset] != asn1IntegerID { |
||||
str := fmt.Sprintf( |
||||
"malformed signature: S integer marker: %#x != %#x", |
||||
sig[sTypeOffset], asn1IntegerID, |
||||
) |
||||
return nil, signatureError(ErrSigInvalidSIntID, str) |
||||
} |
||||
// Zero-length integers are not allowed for S.
|
||||
if sLen == 0 { |
||||
str := "malformed signature: S length is zero" |
||||
return nil, signatureError(ErrSigZeroSLen, str) |
||||
} |
||||
// S must not be negative.
|
||||
if sig[sOffset]&0x80 != 0 { |
||||
str := "malformed signature: S is negative" |
||||
return nil, signatureError(ErrSigNegativeS, str) |
||||
} |
||||
// Null bytes at the start of S are not allowed, unless S would otherwise be
|
||||
// interpreted as a negative number.
|
||||
if sLen > 1 && sig[sOffset] == 0x00 && sig[sOffset+1]&0x80 == 0 { |
||||
str := "malformed signature: S value has too much padding" |
||||
return nil, signatureError(ErrSigTooMuchSPadding, str) |
||||
} |
||||
// The signature is validly encoded per DER at this point, however, enforce
|
||||
// additional restrictions to ensure R and S are in the range [1, N-1] since
|
||||
// valid ECDSA signatures are required to be in that range per spec.
|
||||
//
|
||||
// Also note that while the overflow checks are required to make use of the
|
||||
// specialized mod N scalar type, rejecting zero here is not strictly
|
||||
// required because it is also checked when verifying the signature, but
|
||||
// there really isn't a good reason not to fail early here on signatures
|
||||
// that do not conform to the ECDSA spec.
|
||||
//
|
||||
// Strip leading zeroes from R.
|
||||
rBytes := sig[rOffset : rOffset+rLen] |
||||
for len(rBytes) > 0 && rBytes[0] == 0x00 { |
||||
rBytes = rBytes[1:] |
||||
} |
||||
// R must be in the range [1, N-1]. Notice the check for the maximum number
|
||||
// of bytes is required because SetByteSlice truncates as noted in its
|
||||
// comment so it could otherwise fail to detect the overflow.
|
||||
var r secp256k1.ModNScalar |
||||
if len(rBytes) > 32 { |
||||
str := "invalid signature: R is larger than 256 bits" |
||||
return nil, signatureError(ErrSigRTooBig, str) |
||||
} |
||||
if overflow := r.SetByteSlice(rBytes); overflow { |
||||
str := "invalid signature: R >= group order" |
||||
return nil, signatureError(ErrSigRTooBig, str) |
||||
} |
||||
if r.IsZero() { |
||||
str := "invalid signature: R is 0" |
||||
return nil, signatureError(ErrSigRIsZero, str) |
||||
} |
||||
// Strip leading zeroes from S.
|
||||
sBytes := sig[sOffset : sOffset+sLen] |
||||
for len(sBytes) > 0 && sBytes[0] == 0x00 { |
||||
sBytes = sBytes[1:] |
||||
} |
||||
// S must be in the range [1, N-1]. Notice the check for the maximum number
|
||||
// of bytes is required because SetByteSlice truncates as noted in its
|
||||
// comment so it could otherwise fail to detect the overflow.
|
||||
var s secp256k1.ModNScalar |
||||
if len(sBytes) > 32 { |
||||
str := "invalid signature: S is larger than 256 bits" |
||||
return nil, signatureError(ErrSigSTooBig, str) |
||||
} |
||||
if overflow := s.SetByteSlice(sBytes); overflow { |
||||
str := "invalid signature: S >= group order" |
||||
return nil, signatureError(ErrSigSTooBig, str) |
||||
} |
||||
if s.IsZero() { |
||||
str := "invalid signature: S is 0" |
||||
return nil, signatureError(ErrSigSIsZero, str) |
||||
} |
||||
// Create and return the signature.
|
||||
return NewSignature(&r, &s), nil |
||||
} |
||||
|
||||
// sign generates an ECDSA signature over the secp256k1 curve for the provided
|
||||
// hash (which should be the result of hashing a larger message) using the given
|
||||
// nonce and secret key and returns it along with an additional public key
|
||||
// recovery code and success indicator. Upon success, the produced signature is
|
||||
// deterministic (same message, nonce, and key yield the same signature) and
|
||||
// canonical in accordance with BIP0062.
|
||||
//
|
||||
// Note that signRFC6979 makes use of this function as it is the primary ECDSA
|
||||
// signing logic. It differs in that it accepts a nonce to use when signing and
|
||||
// may not successfully produce a valid signature for the given nonce. It is
|
||||
// primarily separated for testing purposes.
|
||||
func sign(secKey, nonce *secp256k1.ModNScalar, hash []byte) ( |
||||
*Signature, byte, |
||||
bool, |
||||
) { |
||||
// The algorithm for producing an ECDSA signature is given as algorithm 4.29
|
||||
// in [GECC].
|
||||
//
|
||||
// The following is a paraphrased version for reference:
|
||||
//
|
||||
// G = curve generator
|
||||
// N = curve order
|
||||
// d = secret key
|
||||
// m = message
|
||||
// r, s = signature
|
||||
//
|
||||
// 1. Select random nonce k in [1, N-1]
|
||||
// 2. Compute kG
|
||||
// 3. r = kG.x mod N (kG.x is the x coordinate of the point kG)
|
||||
// Repeat from step 1 if r = 0
|
||||
// 4. e = H(m)
|
||||
// 5. s = k^-1(e + dr) mod N
|
||||
// Repeat from step 1 if s = 0
|
||||
// 6. Return (r,s)
|
||||
//
|
||||
// This is slightly modified here to conform to RFC6979 and BIP 62 as
|
||||
// follows:
|
||||
//
|
||||
// A. Instead of selecting a random nonce in step 1, use RFC6979 to generate
|
||||
// a deterministic nonce in [1, N-1] parameterized by the secret key,
|
||||
// message being signed, and an iteration count for the repeat cases
|
||||
// B. Negate s calculated in step 5 if it is > N/2
|
||||
// This is done because both s and its negation are valid signatures
|
||||
// modulo the curve order N, so it forces a consistent choice to reduce
|
||||
// signature malleability
|
||||
//
|
||||
// NOTE: Step 1 is performed by the caller.
|
||||
//
|
||||
// Step 2.
|
||||
//
|
||||
// Compute kG
|
||||
//
|
||||
// Note that the point must be in affine coordinates.
|
||||
k := nonce |
||||
var kG secp256k1.JacobianPoint |
||||
secp256k1.ScalarBaseMultNonConst(k, &kG) |
||||
kG.ToAffine() |
||||
// Step 3.
|
||||
//
|
||||
// r = kG.x mod N
|
||||
// Repeat from step 1 if r = 0
|
||||
r, overflow := fieldToModNScalar(&kG.X) |
||||
if r.IsZero() { |
||||
return nil, 0, false |
||||
} |
||||
// Since the secp256k1 curve has a cofactor of 1, when recovering a
|
||||
// public key from an ECDSA signature over it, there are four possible
|
||||
// candidates corresponding to the following cases:
|
||||
//
|
||||
// 1) The X coord of the random point is < N and its Y coord even
|
||||
// 2) The X coord of the random point is < N and its Y coord is odd
|
||||
// 3) The X coord of the random point is >= N and its Y coord is even
|
||||
// 4) The X coord of the random point is >= N and its Y coord is odd
|
||||
//
|
||||
// Rather than forcing the recovery procedure to check all possible
|
||||
// cases, this creates a recovery code that uniquely identifies which of
|
||||
// the cases apply by making use of 2 bits. Bit 0 identifies the
|
||||
// oddness case and Bit 1 identifies the overflow case (aka when the X
|
||||
// coord >= N).
|
||||
//
|
||||
// It is also worth noting that making use of Hasse's theorem shows
|
||||
// there are around log_2((p-n)/p) ~= -127.65 ~= 1 in 2^127 points where
|
||||
// the X coordinate is >= N. It is not possible to calculate these
|
||||
// points since that would require breaking the ECDLP, but, in practice
|
||||
// this strongly implies with extremely high probability that there are
|
||||
// only a few actual points for which this case is true.
|
||||
pubKeyRecoveryCode := byte(overflow<<1) | byte(kG.Y.IsOddBit()) |
||||
// Step 4.
|
||||
//
|
||||
// e = H(m)
|
||||
//
|
||||
// Note that this actually sets e = H(m) mod N which is correct since
|
||||
// it is only used in step 5 which itself is mod N.
|
||||
var e secp256k1.ModNScalar |
||||
e.SetByteSlice(hash) |
||||
// Step 5 with modification B.
|
||||
//
|
||||
// s = k^-1(e + dr) mod N
|
||||
// Repeat from step 1 if s = 0
|
||||
// s = -s if s > N/2
|
||||
kinv := new(secp256k1.ModNScalar).InverseValNonConst(k) |
||||
s := new(secp256k1.ModNScalar).Mul2(secKey, &r).Add(&e).Mul(kinv) |
||||
if s.IsZero() { |
||||
return nil, 0, false |
||||
} |
||||
if s.IsOverHalfOrder() { |
||||
s.Negate() |
||||
// Negating s corresponds to the random point that would have been
|
||||
// generated by -k (mod N), which necessarily has the opposite
|
||||
// oddness since N is prime, thus flip the pubkey recovery code
|
||||
// oddness bit accordingly.
|
||||
pubKeyRecoveryCode ^= 0x01 |
||||
} |
||||
// Step 6.
|
||||
//
|
||||
// Return (r,s)
|
||||
return NewSignature(&r, s), pubKeyRecoveryCode, true |
||||
} |
||||
|
||||
// signRFC6979 generates a deterministic ECDSA signature according to RFC 6979
|
||||
// and BIP0062 and returns it along with an additional public key recovery code
|
||||
// for efficiently recovering the public key from the signature.
|
||||
func signRFC6979(secKey *secp256k1.SecretKey, hash []byte) ( |
||||
*Signature, |
||||
byte, |
||||
) { |
||||
// The algorithm for producing an ECDSA signature is given as algorithm 4.29
|
||||
// in [GECC].
|
||||
//
|
||||
// The following is a paraphrased version for reference:
|
||||
//
|
||||
// G = curve generator
|
||||
// N = curve order
|
||||
// d = secret key
|
||||
// m = message
|
||||
// r, s = signature
|
||||
//
|
||||
// 1. Select random nonce k in [1, N-1]
|
||||
// 2. Compute kG
|
||||
// 3. r = kG.x mod N (kG.x is the x coordinate of the point kG)
|
||||
// Repeat from step 1 if r = 0
|
||||
// 4. e = H(m)
|
||||
// 5. s = k^-1(e + dr) mod N
|
||||
// Repeat from step 1 if s = 0
|
||||
// 6. Return (r,s)
|
||||
//
|
||||
// This is slightly modified here to conform to RFC6979 and BIP 62 as
|
||||
// follows:
|
||||
//
|
||||
// A. Instead of selecting a random nonce in step 1, use RFC6979 to generate
|
||||
// a deterministic nonce in [1, N-1] parameterized by the secret key,
|
||||
// message being signed, and an iteration count for the repeat cases
|
||||
// B. Negate s calculated in step 5 if it is > N/2
|
||||
// This is done because both s and its negation are valid signatures
|
||||
// modulo the curve order N, so it forces a consistent choice to reduce
|
||||
// signature malleability
|
||||
secKeyScalar := &secKey.Key |
||||
var secKeyBytes [32]byte |
||||
secKeyScalar.PutBytes(&secKeyBytes) |
||||
defer zeroArray32(&secKeyBytes) |
||||
for iteration := uint32(0); ; iteration++ { |
||||
// Step 1 with modification A.
|
||||
//
|
||||
// Generate a deterministic nonce in [1, N-1] parameterized by the
|
||||
// secret key, message being signed, and iteration count.
|
||||
k := secp256k1.NonceRFC6979(secKeyBytes[:], hash, nil, nil, iteration) |
||||
// Steps 2-6.
|
||||
sig, pubKeyRecoveryCode, success := sign(secKeyScalar, k, hash) |
||||
k.Zero() |
||||
if !success { |
||||
continue |
||||
} |
||||
return sig, pubKeyRecoveryCode |
||||
} |
||||
} |
||||
|
||||
// Sign generates an ECDSA signature over the secp256k1 curve for the provided
|
||||
// hash (which should be the result of hashing a larger message) using the given
|
||||
// secret key. The produced signature is deterministic (same message and same
|
||||
// key yield the same signature) and canonical in accordance with RFC6979 and
|
||||
// BIP0062.
|
||||
func Sign(key *secp256k1.SecretKey, hash []byte) *Signature { |
||||
signature, _ := signRFC6979(key, hash) |
||||
return signature |
||||
} |
||||
|
||||
const ( |
||||
// compactSigSize is the size of a compact signature. It consists of a
|
||||
// compact signature recovery code byte followed by the R and S components
|
||||
// serialized as 32-byte big-endian values. 1+32*2 = 65.
|
||||
// for the R and S components. 1+32+32=65.
|
||||
compactSigSize = 65 |
||||
// compactSigMagicOffset is a value used when creating the compact signature
|
||||
// recovery code inherited from Bitcoin and has no meaning, but has been
|
||||
// retained for compatibility. For historical purposes, it was originally
|
||||
// picked to avoid a binary representation that would allow compact
|
||||
// signatures to be mistaken for other components.
|
||||
compactSigMagicOffset = 27 |
||||
// compactSigCompPubKey is a value used when creating the compact signature
|
||||
// recovery code to indicate the original public key was compressed.
|
||||
compactSigCompPubKey = 4 |
||||
// pubKeyRecoveryCodeOddnessBit specifies the bit that indicates the oddess
|
||||
// of the Y coordinate of the random point calculated when creating a
|
||||
// signature.
|
||||
pubKeyRecoveryCodeOddnessBit = 1 << 0 |
||||
// pubKeyRecoveryCodeOverflowBit specifies the bit that indicates the X
|
||||
// coordinate of the random point calculated when creating a signature was
|
||||
// >= N, where N is the order of the group.
|
||||
pubKeyRecoveryCodeOverflowBit = 1 << 1 |
||||
) |
||||
|
||||
// SignCompact produces a compact ECDSA signature over the secp256k1 curve for
|
||||
// the provided hash (which should be the result of hashing a larger message)
|
||||
// using the given secret key. The isCompressedKey parameter specifies if the
|
||||
// produced signature should reference a compressed public key or not.
|
||||
//
|
||||
// Compact signature format:
|
||||
// <1-byte compact sig recovery code><32-byte R><32-byte S>
|
||||
//
|
||||
// The compact sig recovery code is the value 27 + public key recovery code + 4
|
||||
// if the compact signature was created with a compressed public key.
|
||||
func SignCompact( |
||||
key *secp256k1.SecretKey, hash []byte, |
||||
isCompressedKey bool, |
||||
) []byte { |
||||
// Create the signature and associated pubkey recovery code and calculate
|
||||
// the compact signature recovery code.
|
||||
sig, pubKeyRecoveryCode := signRFC6979(key, hash) |
||||
compactSigRecoveryCode := compactSigMagicOffset + pubKeyRecoveryCode |
||||
if isCompressedKey { |
||||
compactSigRecoveryCode += compactSigCompPubKey |
||||
} |
||||
// Output <compactSigRecoveryCode><32-byte R><32-byte S>.
|
||||
var b [compactSigSize]byte |
||||
b[0] = compactSigRecoveryCode |
||||
sig.r.PutBytesUnchecked(b[1:33]) |
||||
sig.s.PutBytesUnchecked(b[33:65]) |
||||
return b[:] |
||||
} |
||||
|
||||
// RecoverCompact attempts to recover the secp256k1 public key from the provided
|
||||
// compact signature and message hash. It first verifies the signature, and, if
|
||||
// the signature matches then the recovered public key will be returned as well
|
||||
// as a boolean indicating whether or not the original key was compressed.
|
||||
func RecoverCompact(signature, hash []byte) ( |
||||
*secp256k1.PublicKey, bool, error, |
||||
) { |
||||
// The following is very loosely based on the information and algorithm that
|
||||
// describes recovering a public key from and ECDSA signature in section
|
||||
// 4.1.6 of [SEC1].
|
||||
//
|
||||
// Given the following parameters:
|
||||
//
|
||||
// G = curve generator
|
||||
// N = group order
|
||||
// P = field prime
|
||||
// Q = public key
|
||||
// m = message
|
||||
// e = hash of the message
|
||||
// r, s = signature
|
||||
// X = random point used when creating signature whose x coordinate is r
|
||||
//
|
||||
// The equation to recover a public key candidate from an ECDSA signature
|
||||
// is:
|
||||
// Q = r^-1(sX - eG).
|
||||
//
|
||||
// This can be verified by plugging it in for Q in the sig verification
|
||||
// equation:
|
||||
// X = s^-1(eG + rQ) (mod N)
|
||||
// => s^-1(eG + r(r^-1(sX - eG))) (mod N)
|
||||
// => s^-1(eG + sX - eG) (mod N)
|
||||
// => s^-1(sX) (mod N)
|
||||
// => X (mod N)
|
||||
//
|
||||
// However, note that since r is the x coordinate mod N from a random point
|
||||
// that was originally mod P, and the cofactor of the secp256k1 curve is 1,
|
||||
// there are four possible points that the original random point could have
|
||||
// been to produce r: (r,y), (r,-y), (r+N,y), and (r+N,-y). At least 2 of
|
||||
// those points will successfully verify, and all 4 will successfully verify
|
||||
// when the original x coordinate was in the range [N+1, P-1], but in any
|
||||
// case, only one of them corresponds to the original secret key used.
|
||||
//
|
||||
// The method described by section 4.1.6 of [SEC1] to determine which one is
|
||||
// the correct one involves calculating each possibility as a candidate
|
||||
// public key and comparing the candidate to the authentic public key. It
|
||||
// also hints that it is possible to generate the signature in a such a
|
||||
// way that only one of the candidate public keys is viable.
|
||||
//
|
||||
// A more efficient approach that is specific to the secp256k1 curve is used
|
||||
// here instead which is to produce a "pubkey recovery code" when signing
|
||||
// that uniquely identifies which of the 4 possibilities is correct for the
|
||||
// original random point and using that to recover the pubkey directly as
|
||||
// follows:
|
||||
//
|
||||
// 1. Fail if r and s are not in [1, N-1]
|
||||
// 2. Convert r to integer mod P
|
||||
// 3. If pubkey recovery code overflow bit is set:
|
||||
// 3.1 Fail if r + N >= P
|
||||
// 3.2 r = r + N (mod P)
|
||||
// 4. y = +sqrt(r^3 + 7) (mod P)
|
||||
// 4.1 Fail if y does not exist
|
||||
// 4.2 y = -y if needed to match pubkey recovery code oddness bit
|
||||
// 5. X = (r, y)
|
||||
// 6. e = H(m) mod N
|
||||
// 7. w = r^-1 mod N
|
||||
// 8. u1 = -(e * w) mod N
|
||||
// u2 = s * w mod N
|
||||
// 9. Q = u1G + u2X
|
||||
// 10. Fail if Q is the point at infinity
|
||||
//
|
||||
// A compact signature consists of a recovery byte followed by the R and
|
||||
// S components serialized as 32-byte big-endian values.
|
||||
if len(signature) != compactSigSize { |
||||
str := fmt.Sprintf( |
||||
"malformed signature: wrong size: %d != %d", |
||||
len(signature), compactSigSize, |
||||
) |
||||
return nil, false, signatureError(ErrSigInvalidLen, str) |
||||
} |
||||
// Parse and validate the compact signature recovery code.
|
||||
const ( |
||||
minValidCode = compactSigMagicOffset |
||||
maxValidCode = compactSigMagicOffset + compactSigCompPubKey + 3 |
||||
) |
||||
sigRecoveryCode := signature[0] |
||||
if sigRecoveryCode < minValidCode || sigRecoveryCode > maxValidCode { |
||||
str := fmt.Sprintf( |
||||
"invalid signature: public key recovery code %d is "+ |
||||
"not in the valid range [%d, %d]", sigRecoveryCode, |
||||
minValidCode, |
||||
maxValidCode, |
||||
) |
||||
return nil, false, signatureError(ErrSigInvalidRecoveryCode, str) |
||||
} |
||||
sigRecoveryCode -= compactSigMagicOffset |
||||
wasCompressed := sigRecoveryCode&compactSigCompPubKey != 0 |
||||
pubKeyRecoveryCode := sigRecoveryCode & 3 |
||||
// Step 1.
|
||||
//
|
||||
// Parse and validate the R and S signature components.
|
||||
//
|
||||
// Fail if r and s are not in [1, N-1].
|
||||
var r, s secp256k1.ModNScalar |
||||
if overflow := r.SetByteSlice(signature[1:33]); overflow { |
||||
str := "invalid signature: R >= group order" |
||||
return nil, false, signatureError(ErrSigRTooBig, str) |
||||
} |
||||
if r.IsZero() { |
||||
str := "invalid signature: R is 0" |
||||
return nil, false, signatureError(ErrSigRIsZero, str) |
||||
} |
||||
if overflow := s.SetByteSlice(signature[33:]); overflow { |
||||
str := "invalid signature: S >= group order" |
||||
return nil, false, signatureError(ErrSigSTooBig, str) |
||||
} |
||||
if s.IsZero() { |
||||
str := "invalid signature: S is 0" |
||||
return nil, false, signatureError(ErrSigSIsZero, str) |
||||
} |
||||
// Step 2.
|
||||
//
|
||||
// Convert r to integer mod P.
|
||||
fieldR := modNScalarToField(&r) |
||||
// Step 3.
|
||||
//
|
||||
// If pubkey recovery code overflow bit is set:
|
||||
if pubKeyRecoveryCode&pubKeyRecoveryCodeOverflowBit != 0 { |
||||
// Step 3.1.
|
||||
//
|
||||
// Fail if r + N >= P
|
||||
//
|
||||
// Either the signature or the recovery code must be invalid if the
|
||||
// recovery code overflow bit is set and adding N to the R component
|
||||
// would exceed the field prime since R originally came from the X
|
||||
// coordinate of a random point on the curve.
|
||||
if fieldR.IsGtOrEqPrimeMinusOrder() { |
||||
str := "invalid signature: signature R + N >= P" |
||||
return nil, false, signatureError(ErrSigOverflowsPrime, str) |
||||
} |
||||
// Step 3.2.
|
||||
//
|
||||
// r = r + N (mod P)
|
||||
fieldR.Add(&orderAsFieldVal) |
||||
} |
||||
// Step 4.
|
||||
//
|
||||
// y = +sqrt(r^3 + 7) (mod P)
|
||||
// Fail if y does not exist.
|
||||
// y = -y if needed to match pubkey recovery code oddness bit
|
||||
//
|
||||
// The signature must be invalid if the calculation fails because the X
|
||||
// coord originally came from a random point on the curve which means there
|
||||
// must be a Y coord that satisfies the equation for a valid signature.
|
||||
oddY := pubKeyRecoveryCode&pubKeyRecoveryCodeOddnessBit != 0 |
||||
var y secp256k1.FieldVal |
||||
if valid := secp256k1.DecompressY(&fieldR, oddY, &y); !valid { |
||||
str := "invalid signature: not for a valid curve point" |
||||
return nil, false, signatureError(ErrPointNotOnCurve, str) |
||||
} |
||||
// Step 5.
|
||||
//
|
||||
// X = (r, y)
|
||||
var X secp256k1.JacobianPoint |
||||
X.X.Set(fieldR.Normalize()) |
||||
X.Y.Set(y.Normalize()) |
||||
X.Z.SetInt(1) |
||||
// Step 6.
|
||||
//
|
||||
// e = H(m) mod N
|
||||
var e secp256k1.ModNScalar |
||||
e.SetByteSlice(hash) |
||||
// Step 7.
|
||||
//
|
||||
// w = r^-1 mod N
|
||||
w := new(secp256k1.ModNScalar).InverseValNonConst(&r) |
||||
// Step 8.
|
||||
//
|
||||
// u1 = -(e * w) mod N
|
||||
// u2 = s * w mod N
|
||||
u1 := new(secp256k1.ModNScalar).Mul2(&e, w).Negate() |
||||
u2 := new(secp256k1.ModNScalar).Mul2(&s, w) |
||||
// Step 9.
|
||||
//
|
||||
// Q = u1G + u2X
|
||||
var Q, u1G, u2X secp256k1.JacobianPoint |
||||
secp256k1.ScalarBaseMultNonConst(u1, &u1G) |
||||
secp256k1.ScalarMultNonConst(u2, &X, &u2X) |
||||
secp256k1.AddNonConst(&u1G, &u2X, &Q) |
||||
// Step 10.
|
||||
//
|
||||
// Fail if Q is the point at infinity.
|
||||
//
|
||||
// Either the signature or the pubkey recovery code must be invalid if the
|
||||
// recovered pubkey is the point at infinity.
|
||||
if (Q.X.IsZero() && Q.Y.IsZero()) || Q.Z.IsZero() { |
||||
str := "invalid signature: recovered pubkey is the point at infinity" |
||||
return nil, false, signatureError(ErrPointNotOnCurve, str) |
||||
} |
||||
// Notice that the public key is in affine coordinates.
|
||||
Q.ToAffine() |
||||
pubKey := secp256k1.NewPublicKey(&Q.X, &Q.Y) |
||||
return pubKey, wasCompressed, nil |
||||
} |
||||
File diff suppressed because it is too large
Load Diff
@ -1,24 +0,0 @@
@@ -1,24 +0,0 @@
|
||||
// Copyright (c) 2013-2021 The btcsuite developers
|
||||
// Copyright (c) 2015-2021 The Decred developers
|
||||
|
||||
package btcec |
||||
|
||||
import ( |
||||
"next.orly.dev/pkg/crypto/ec/secp256k1" |
||||
) |
||||
|
||||
// Error identifies an error related to public key cryptography using a
|
||||
// sec256k1 curve. It has full support for errors.Is and errors.As, so the
|
||||
// caller can ascertain the specific reason for the error by checking the
|
||||
// underlying error.
|
||||
type Error = secp256k1.Error |
||||
|
||||
// ErrorKind identifies a kind of error. It has full support for errors.Is and
|
||||
// errors.As, so the caller can directly check against an error kind when
|
||||
// determining the reason for an error.
|
||||
type ErrorKind = secp256k1.ErrorKind |
||||
|
||||
// makeError creates an secp256k1.Error given a set of arguments.
|
||||
func makeError(kind ErrorKind, desc string) Error { |
||||
return Error{Err: kind, Description: desc} |
||||
} |
||||
@ -1,45 +0,0 @@
@@ -1,45 +0,0 @@
|
||||
package btcec |
||||
|
||||
import ( |
||||
"next.orly.dev/pkg/crypto/ec/secp256k1" |
||||
) |
||||
|
||||
// FieldVal implements optimized fixed-precision arithmetic over the secp256k1
|
||||
// finite field. This means all arithmetic is performed modulo
|
||||
// '0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f'.
|
||||
//
|
||||
// WARNING: Since it is so important for the field arithmetic to be extremely
|
||||
// fast for high performance crypto, this type does not perform any validation
|
||||
// of documented preconditions where it ordinarily would. As a result, it is
|
||||
// IMPERATIVE for callers to understand some key concepts that are described
|
||||
// below and ensure the methods are called with the necessary preconditions
|
||||
// that each method is documented with. For example, some methods only give the
|
||||
// correct result if the field value is normalized and others require the field
|
||||
// values involved to have a maximum magnitude and THERE ARE NO EXPLICIT CHECKS
|
||||
// TO ENSURE THOSE PRECONDITIONS ARE SATISFIED. This does, unfortunately, make
|
||||
// the type more difficult to use correctly and while I typically prefer to
|
||||
// ensure all state and input is valid for most code, this is a bit of an
|
||||
// exception because those extra checks really add up in what ends up being
|
||||
// critical hot paths.
|
||||
//
|
||||
// The first key concept when working with this type is normalization. In order
|
||||
// to avoid the need to propagate a ton of carries, the internal representation
|
||||
// provides additional overflow bits for each word of the overall 256-bit
|
||||
// value. This means that there are multiple internal representations for the
|
||||
// same value and, as a result, any methods that rely on comparison of the
|
||||
// value, such as equality and oddness determination, require the caller to
|
||||
// provide a normalized value.
|
||||
//
|
||||
// The second key concept when working with this type is magnitude. As
|
||||
// previously mentioned, the internal representation provides additional
|
||||
// overflow bits which means that the more math operations that are performed
|
||||
// on the field value between normalizations, the more those overflow bits
|
||||
// accumulate. The magnitude is effectively that maximum possible number of
|
||||
// those overflow bits that could possibly be required as a result of a given
|
||||
// operation. Since there are only a limited number of overflow bits available,
|
||||
// this implies that the max possible magnitude MUST be tracked by the caller
|
||||
// and the caller MUST normalize the field value if a given operation would
|
||||
// cause the magnitude of the result to exceed the max allowed value.
|
||||
//
|
||||
// IMPORTANT: The max allowed magnitude of a field value is 64.
|
||||
type FieldVal = secp256k1.FieldVal |
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue