Add code to produce and verify compact signatures.
The format used is identical to that used in bitcoind.
This commit is contained in:
parent
218906a91e
commit
ff3fac426d
5 changed files with 297 additions and 41 deletions
2
btcec.go
2
btcec.go
|
@ -38,6 +38,7 @@ var (
|
||||||
type KoblitzCurve struct {
|
type KoblitzCurve struct {
|
||||||
*elliptic.CurveParams
|
*elliptic.CurveParams
|
||||||
q *big.Int
|
q *big.Int
|
||||||
|
H int // cofactor of the curve.
|
||||||
}
|
}
|
||||||
|
|
||||||
// Params returns the parameters for the curve.
|
// Params returns the parameters for the curve.
|
||||||
|
@ -652,6 +653,7 @@ func initS256() {
|
||||||
secp256k1.Gx, _ = new(big.Int).SetString("79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798", 16)
|
secp256k1.Gx, _ = new(big.Int).SetString("79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798", 16)
|
||||||
secp256k1.Gy, _ = new(big.Int).SetString("483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8", 16)
|
secp256k1.Gy, _ = new(big.Int).SetString("483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8", 16)
|
||||||
secp256k1.BitSize = 256
|
secp256k1.BitSize = 256
|
||||||
|
secp256k1.H = 1
|
||||||
secp256k1.q = new(big.Int).Div(new(big.Int).Add(secp256k1.P,
|
secp256k1.q = new(big.Int).Div(new(big.Int).Add(secp256k1.P,
|
||||||
big.NewInt(1)), big.NewInt(4))
|
big.NewInt(1)), big.NewInt(4))
|
||||||
}
|
}
|
||||||
|
|
47
pubkey.go
47
pubkey.go
|
@ -14,6 +14,32 @@ func isOdd(a *big.Int) bool {
|
||||||
return a.Bit(0) == 1
|
return a.Bit(0) == 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// decompressPoint decompresses a point on the given curve given the X point and
|
||||||
|
// the solution to use.
|
||||||
|
func decompressPoint(curve *KoblitzCurve, x *big.Int, ybit bool) (*big.Int, error) {
|
||||||
|
// TODO(oga) This will probably only work for secp256k1 due to
|
||||||
|
// optimisations.
|
||||||
|
|
||||||
|
// Y = +-sqrt(x^3 + B)
|
||||||
|
x3 := new(big.Int).Mul(x, x)
|
||||||
|
x3.Mul(x3, x)
|
||||||
|
x3.Add(x3, curve.Params().B)
|
||||||
|
|
||||||
|
// now calculate sqrt mod p of x2 + B
|
||||||
|
// This code used to do a full sqrt based on tonelli/shanks,
|
||||||
|
// but this was replaced by the algorithms referenced in
|
||||||
|
// https://bitcointalk.org/index.php?topic=162805.msg1712294#msg1712294
|
||||||
|
y := new(big.Int).Exp(x3, curve.QPlus1Div4(), curve.Params().P)
|
||||||
|
|
||||||
|
if ybit != isOdd(y) {
|
||||||
|
y.Sub(curve.Params().P, y)
|
||||||
|
}
|
||||||
|
if ybit != isOdd(y) {
|
||||||
|
return nil, fmt.Errorf("ybit doesn't match oddness")
|
||||||
|
}
|
||||||
|
return y, nil
|
||||||
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
pubkeyCompressed byte = 0x2 // y_bit + x coord
|
pubkeyCompressed byte = 0x2 // y_bit + x coord
|
||||||
pubkeyUncompressed byte = 0x4 // x coord + y coord
|
pubkeyUncompressed byte = 0x4 // x coord + y coord
|
||||||
|
@ -53,25 +79,10 @@ func ParsePubKey(pubKeyStr []byte, curve *KoblitzCurve) (key *ecdsa.PublicKey, e
|
||||||
"pubkey string: %d", pubKeyStr[0])
|
"pubkey string: %d", pubKeyStr[0])
|
||||||
}
|
}
|
||||||
pubkey.X = new(big.Int).SetBytes(pubKeyStr[1:33])
|
pubkey.X = new(big.Int).SetBytes(pubKeyStr[1:33])
|
||||||
// Y = +-sqrt(x^3 + B)
|
pubkey.Y, err = decompressPoint(curve, pubkey.X, ybit)
|
||||||
x3 := new(big.Int).Mul(pubkey.X, pubkey.X)
|
if err != nil {
|
||||||
x3.Mul(x3, pubkey.X)
|
return nil, err
|
||||||
x3.Add(x3, pubkey.Curve.Params().B)
|
|
||||||
|
|
||||||
// now calculate sqrt mod p of x2 + B
|
|
||||||
// This code used to do a full sqrt based on tonelli/shanks,
|
|
||||||
// but this was replaced by the algorithms referenced in
|
|
||||||
// https://bitcointalk.org/index.php?topic=162805.msg1712294#msg1712294
|
|
||||||
y := new(big.Int).Exp(x3, curve.QPlus1Div4(), pubkey.Curve.Params().P)
|
|
||||||
|
|
||||||
if ybit != isOdd(y) {
|
|
||||||
y.Sub(pubkey.Curve.Params().P, y)
|
|
||||||
}
|
}
|
||||||
if ybit != isOdd(y) {
|
|
||||||
return nil, fmt.Errorf("ybit doesn't match oddness")
|
|
||||||
}
|
|
||||||
|
|
||||||
pubkey.Y = y
|
|
||||||
default: // wrong!
|
default: // wrong!
|
||||||
return nil, fmt.Errorf("invalid pub key length %d",
|
return nil, fmt.Errorf("invalid pub key length %d",
|
||||||
len(pubKeyStr))
|
len(pubKeyStr))
|
||||||
|
|
168
signature.go
168
signature.go
|
@ -5,7 +5,9 @@
|
||||||
package btcec
|
package btcec
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto/ecdsa"
|
||||||
"crypto/elliptic"
|
"crypto/elliptic"
|
||||||
|
"crypto/rand"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
@ -213,3 +215,169 @@ func canonicalPadding(b []byte) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// hashToInt converts a hash value to an integer. There is some disagreement
|
||||||
|
// about how this is done. [NSA] suggests that this is done in the obvious
|
||||||
|
// manner, but [SECG] truncates the hash to the bit-length of the curve order
|
||||||
|
// first. We follow [SECG] because that's what OpenSSL does. Additionally,
|
||||||
|
// OpenSSL right shifts excess bits from the number if the hash is too large
|
||||||
|
// and we mirror that too.
|
||||||
|
// This is borrowed from crypto/ecdsa.
|
||||||
|
func hashToInt(hash []byte, c elliptic.Curve) *big.Int {
|
||||||
|
orderBits := c.Params().N.BitLen()
|
||||||
|
orderBytes := (orderBits + 7) / 8
|
||||||
|
if len(hash) > orderBytes {
|
||||||
|
hash = hash[:orderBytes]
|
||||||
|
}
|
||||||
|
|
||||||
|
ret := new(big.Int).SetBytes(hash)
|
||||||
|
excess := len(hash)*8 - orderBits
|
||||||
|
if excess > 0 {
|
||||||
|
ret.Rsh(ret, uint(excess))
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
// recoverKeyFromSignature recoves a public key from the signature "sig" on the
|
||||||
|
// given message hash "msg". Based on the algorithm found in section 5.1.5 of
|
||||||
|
// SEC 1 Ver 2.0, page 47-48 (53 and 54 in the pdf). This performs the details
|
||||||
|
// in the inner loop in Step 1. The counter provided is actually the j parameter
|
||||||
|
// of the loop * 2 - on the first iteration of j we do the R case, else the -R
|
||||||
|
// case in step 1.6. This counter is used in the bitcoin compressed signature
|
||||||
|
// format and thus we match bitcoind's behaviour here.
|
||||||
|
func recoverKeyFromSignature(curve *KoblitzCurve, sig *Signature, msg []byte,
|
||||||
|
iter int, doChecks bool) (*ecdsa.PublicKey, error) {
|
||||||
|
// 1.1 x = (n * i) + r
|
||||||
|
Rx := new(big.Int).Mul(curve.Params().N,
|
||||||
|
new(big.Int).SetInt64(int64(iter/2)))
|
||||||
|
Rx.Add(Rx, sig.R)
|
||||||
|
if Rx.Cmp(curve.Params().P) != -1 {
|
||||||
|
return nil, errors.New("calculated Rx is larger than curve P")
|
||||||
|
}
|
||||||
|
|
||||||
|
// convert 02<Rx> to point R. (step 1.2 and 1.3). If we are on an odd
|
||||||
|
// iteration then 1.6 will be done with -R, so we calculate the other
|
||||||
|
// term when uncompressing the point.
|
||||||
|
Ry, err := decompressPoint(curve, Rx, iter%2 == 1)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1.4 Check n*R is point at infinity
|
||||||
|
if doChecks {
|
||||||
|
nRx, nRy := curve.ScalarMult(Rx, Ry, curve.Params().N.Bytes())
|
||||||
|
if nRx.Sign() != 0 || nRy.Sign() != 0 {
|
||||||
|
return nil, errors.New("R*n does not equal the point at infinity")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1.5 calculate e from message using the same algorithm as ecdsa
|
||||||
|
// signature calculation.
|
||||||
|
e := hashToInt(msg, curve)
|
||||||
|
|
||||||
|
// Step 1.6.1:
|
||||||
|
// We calculate the two terms sR and eG separately multiplied by the
|
||||||
|
// inverse of r (from the signature). We then add them to calculate
|
||||||
|
// Q = r^-1(sR-eG)
|
||||||
|
invr := new(big.Int).ModInverse(sig.R, curve.Params().N)
|
||||||
|
|
||||||
|
// first term.
|
||||||
|
invrS := new(big.Int).Mul(invr, sig.S)
|
||||||
|
invrS.Mod(invrS, curve.Params().N)
|
||||||
|
sRx, sRy := curve.ScalarMult(Rx, Ry, invrS.Bytes())
|
||||||
|
|
||||||
|
// second term.
|
||||||
|
e.Neg(e)
|
||||||
|
e.Mod(e, curve.Params().N)
|
||||||
|
e.Mul(e, invr)
|
||||||
|
e.Mod(e, curve.Params().N)
|
||||||
|
minuseGx, minuseGy := curve.ScalarBaseMult(e.Bytes())
|
||||||
|
|
||||||
|
// TODO(oga) this would be faster if we did a mult and add in one
|
||||||
|
// step to prevent the jacobian conversion back and forth.
|
||||||
|
Qx, Qy := curve.Add(sRx, sRy, minuseGx, minuseGy)
|
||||||
|
|
||||||
|
return &ecdsa.PublicKey{
|
||||||
|
Curve: curve,
|
||||||
|
X: Qx,
|
||||||
|
Y: Qy,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SignCompact produces a compact signature of the data in hash with the given
|
||||||
|
// private key on the given koblitz curve. The isCompressed parameter should
|
||||||
|
// be used to detail if the given signature should reference a compressed
|
||||||
|
// public key or not. If successful the bytes of the compact signature will be
|
||||||
|
// returned in the format:
|
||||||
|
// <(byte of 27+public key solution)+4 if compressed >< padded bytes for signature R><padded bytes for signature S>
|
||||||
|
// where the R and S parameters are padde up to the bitlengh of the curve.
|
||||||
|
func SignCompact(curve *KoblitzCurve, key *ecdsa.PrivateKey,
|
||||||
|
hash []byte, isCompressedKey bool) ([]byte, error) {
|
||||||
|
r, s, err := ecdsa.Sign(rand.Reader, key, hash)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
sig := &Signature{R: r, S: s}
|
||||||
|
// bitcoind checks the bit length of R and S here. The ecdsa signature
|
||||||
|
// algorithm returns R and S mod N therefore they will be the bitsize of
|
||||||
|
// the curve, and thus correctly sized.
|
||||||
|
for i := 0; i < (curve.H+1)*2; i++ {
|
||||||
|
pk, err := recoverKeyFromSignature(curve, sig, hash, i, true)
|
||||||
|
if err == nil && pk.X.Cmp(key.X) == 0 && pk.Y.Cmp(key.Y) == 0 {
|
||||||
|
result := make([]byte, 1, 2*(curve.BitSize/8)+1)
|
||||||
|
result[0] = 27 + byte(i)
|
||||||
|
if isCompressedKey {
|
||||||
|
result[0] += 4
|
||||||
|
}
|
||||||
|
// Not sure this needs rounding but safer to do so.
|
||||||
|
curvelen := (curve.BitSize + 7) / 8
|
||||||
|
|
||||||
|
// Pad R and S to curvelen if needed.
|
||||||
|
bytelen := (sig.R.BitLen() + 7) / 8
|
||||||
|
if bytelen < curvelen {
|
||||||
|
result = append(result,
|
||||||
|
make([]byte, curvelen-bytelen)...)
|
||||||
|
}
|
||||||
|
result = append(result, sig.R.Bytes()...)
|
||||||
|
|
||||||
|
bytelen = (sig.S.BitLen() + 7) / 8
|
||||||
|
if bytelen < curvelen {
|
||||||
|
result = append(result,
|
||||||
|
make([]byte, curvelen-bytelen)...)
|
||||||
|
}
|
||||||
|
result = append(result, sig.S.Bytes()...)
|
||||||
|
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, errors.New("no valid solution for pubkey found")
|
||||||
|
}
|
||||||
|
|
||||||
|
// RecoverCompact verifies the compact signature "signature" of "hash" for the
|
||||||
|
// Koblitz curve in "curve". If the signature matches then the recovered public
|
||||||
|
// key will be returned as well as a boolen if the original key was compressed
|
||||||
|
// or not, else an error will be returned.
|
||||||
|
func RecoverCompact(curve *KoblitzCurve, signature,
|
||||||
|
hash []byte) (*ecdsa.PublicKey, bool, error) {
|
||||||
|
bitlen := (curve.BitSize + 7) / 8
|
||||||
|
if len(signature) != 1+bitlen*2 {
|
||||||
|
return nil, false, errors.New("invalid compact signature size")
|
||||||
|
}
|
||||||
|
|
||||||
|
iteration := int((signature[0] - 27) & ^byte(4))
|
||||||
|
|
||||||
|
// format is <header byte><bitlen R><bitlen S>
|
||||||
|
sig := &Signature{
|
||||||
|
R: new(big.Int).SetBytes(signature[1 : bitlen+1]),
|
||||||
|
S: new(big.Int).SetBytes(signature[bitlen+1:]),
|
||||||
|
}
|
||||||
|
// The iteration used here was encoded
|
||||||
|
key, err := recoverKeyFromSignature(curve, sig, hash, iteration, false)
|
||||||
|
if err != nil {
|
||||||
|
return nil, false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return key, ((signature[0] - 27) & 4) == 4, nil
|
||||||
|
}
|
||||||
|
|
|
@ -6,6 +6,9 @@ package btcec_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"crypto/ecdsa"
|
||||||
|
"crypto/rand"
|
||||||
|
"fmt"
|
||||||
"github.com/conformal/btcec"
|
"github.com/conformal/btcec"
|
||||||
"math/big"
|
"math/big"
|
||||||
"testing"
|
"testing"
|
||||||
|
@ -420,3 +423,70 @@ func TestSignatureSerialize(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func testSignCompact(t *testing.T, tag string, curve *btcec.KoblitzCurve,
|
||||||
|
data []byte, isCompressed bool) {
|
||||||
|
priv, _ := ecdsa.GenerateKey(curve, rand.Reader)
|
||||||
|
|
||||||
|
hashed := []byte("testing")
|
||||||
|
sig, err := btcec.SignCompact(curve, priv, hashed, isCompressed)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("%s: error signing: %s", tag, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
pk, wasCompressed, err := btcec.RecoverCompact(curve, sig, hashed)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("%s: error recovering: %s", tag, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if pk.X.Cmp(priv.X) != 0 || pk.Y.Cmp(priv.Y) != 0 {
|
||||||
|
t.Errorf("%s: recovered pubkey doesn't match original "+
|
||||||
|
"(%v,%v) vs (%v,%v) ", tag, pk.X, pk.Y, priv.X, priv.Y)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if wasCompressed != isCompressed {
|
||||||
|
t.Errorf("%s: recovered pubkey doesn't match compressed state "+
|
||||||
|
"(%v vs %v)", tag, isCompressed, wasCompressed)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we change the compressed bit we should get the same key back,
|
||||||
|
// but the compressed flag should be reversed.
|
||||||
|
if isCompressed {
|
||||||
|
sig[0] -= 4
|
||||||
|
} else {
|
||||||
|
sig[0] += 4
|
||||||
|
}
|
||||||
|
|
||||||
|
pk, wasCompressed, err = btcec.RecoverCompact(curve, sig, hashed)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("%s: error recovering (2): %s", tag, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if pk.X.Cmp(priv.X) != 0 || pk.Y.Cmp(priv.Y) != 0 {
|
||||||
|
t.Errorf("%s: recovered pubkey (2) doesn't match original "+
|
||||||
|
"(%v,%v) vs (%v,%v) ", tag, pk.X, pk.Y, priv.X, priv.Y)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if wasCompressed == isCompressed {
|
||||||
|
t.Errorf("%s: recovered pubkey doesn't match reversed "+
|
||||||
|
"compressed state (%v vs %v)", tag, isCompressed,
|
||||||
|
wasCompressed)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSignCompact(t *testing.T) {
|
||||||
|
for i := 0; i < 256; i++ {
|
||||||
|
name := fmt.Sprintf("test %d", i)
|
||||||
|
data := make([]byte, 32)
|
||||||
|
_, err := rand.Read(data)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("failed to read random data for %s", name)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
compressed := i%2 != 0
|
||||||
|
testSignCompact(t, name, btcec.S256(), data, compressed)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -10,50 +10,55 @@ github.com/conformal/btcec/field.go fieldVal.PutBytes 100.00% (32/32)
|
||||||
github.com/conformal/btcec/btcec.go KoblitzCurve.addZ1EqualsZ2 100.00% (30/30)
|
github.com/conformal/btcec/btcec.go KoblitzCurve.addZ1EqualsZ2 100.00% (30/30)
|
||||||
github.com/conformal/btcec/btcec.go KoblitzCurve.addZ1AndZ2EqualsOne 100.00% (29/29)
|
github.com/conformal/btcec/btcec.go KoblitzCurve.addZ1AndZ2EqualsOne 100.00% (29/29)
|
||||||
github.com/conformal/btcec/btcec.go KoblitzCurve.addJacobian 100.00% (22/22)
|
github.com/conformal/btcec/btcec.go KoblitzCurve.addJacobian 100.00% (22/22)
|
||||||
github.com/conformal/btcec/btcec.go KoblitzCurve.doubleZ1EqualsOne 100.00% (18/18)
|
|
||||||
github.com/conformal/btcec/btcec.go KoblitzCurve.doubleGeneric 100.00% (18/18)
|
github.com/conformal/btcec/btcec.go KoblitzCurve.doubleGeneric 100.00% (18/18)
|
||||||
|
github.com/conformal/btcec/btcec.go KoblitzCurve.doubleZ1EqualsOne 100.00% (18/18)
|
||||||
github.com/conformal/btcec/signature.go Signature.Serialize 100.00% (13/13)
|
github.com/conformal/btcec/signature.go Signature.Serialize 100.00% (13/13)
|
||||||
github.com/conformal/btcec/btcec.go KoblitzCurve.fieldJacobianToBigAffine 100.00% (12/12)
|
github.com/conformal/btcec/btcec.go KoblitzCurve.fieldJacobianToBigAffine 100.00% (12/12)
|
||||||
github.com/conformal/btcec/field.go fieldVal.MulInt 100.00% (12/12)
|
github.com/conformal/btcec/field.go fieldVal.MulInt 100.00% (12/12)
|
||||||
github.com/conformal/btcec/field.go fieldVal.Add2 100.00% (11/11)
|
|
||||||
github.com/conformal/btcec/field.go fieldVal.Add 100.00% (11/11)
|
github.com/conformal/btcec/field.go fieldVal.Add 100.00% (11/11)
|
||||||
github.com/conformal/btcec/field.go fieldVal.NegateVal 100.00% (11/11)
|
github.com/conformal/btcec/field.go fieldVal.Add2 100.00% (11/11)
|
||||||
github.com/conformal/btcec/field.go fieldVal.SetBytes 100.00% (11/11)
|
github.com/conformal/btcec/field.go fieldVal.SetBytes 100.00% (11/11)
|
||||||
github.com/conformal/btcec/btcec.go KoblitzCurve.ScalarMult 100.00% (10/10)
|
github.com/conformal/btcec/field.go fieldVal.NegateVal 100.00% (11/11)
|
||||||
github.com/conformal/btcec/btcec.go KoblitzCurve.Add 100.00% (10/10)
|
|
||||||
github.com/conformal/btcec/field.go fieldVal.Zero 100.00% (10/10)
|
github.com/conformal/btcec/field.go fieldVal.Zero 100.00% (10/10)
|
||||||
|
github.com/conformal/btcec/btcec.go KoblitzCurve.Add 100.00% (10/10)
|
||||||
|
github.com/conformal/btcec/btcec.go KoblitzCurve.ScalarMult 100.00% (10/10)
|
||||||
github.com/conformal/btcec/btcec.go KoblitzCurve.doubleJacobian 100.00% (9/9)
|
github.com/conformal/btcec/btcec.go KoblitzCurve.doubleJacobian 100.00% (9/9)
|
||||||
github.com/conformal/btcec/signature.go canonicalizeInt 100.00% (8/8)
|
github.com/conformal/btcec/btcec.go initS256 100.00% (9/9)
|
||||||
github.com/conformal/btcec/pubkey.go PublicKey.SerializeHybrid 100.00% (8/8)
|
github.com/conformal/btcec/pubkey.go PublicKey.SerializeHybrid 100.00% (8/8)
|
||||||
github.com/conformal/btcec/btcec.go initS256 100.00% (8/8)
|
github.com/conformal/btcec/signature.go canonicalizeInt 100.00% (8/8)
|
||||||
github.com/conformal/btcec/pubkey.go PublicKey.SerializeCompressed 100.00% (7/7)
|
github.com/conformal/btcec/pubkey.go PublicKey.SerializeCompressed 100.00% (7/7)
|
||||||
github.com/conformal/btcec/btcec.go KoblitzCurve.Double 100.00% (7/7)
|
github.com/conformal/btcec/btcec.go KoblitzCurve.Double 100.00% (7/7)
|
||||||
github.com/conformal/btcec/field.go fieldVal.SetByteSlice 100.00% (5/5)
|
|
||||||
github.com/conformal/btcec/pubkey.go PublicKey.SerializeUncompressed 100.00% (5/5)
|
github.com/conformal/btcec/pubkey.go PublicKey.SerializeUncompressed 100.00% (5/5)
|
||||||
|
github.com/conformal/btcec/field.go fieldVal.SetByteSlice 100.00% (5/5)
|
||||||
github.com/conformal/btcec/pubkey.go pad 100.00% (5/5)
|
github.com/conformal/btcec/pubkey.go pad 100.00% (5/5)
|
||||||
|
github.com/conformal/btcec/btcec.go KoblitzCurve.bigAffineToField 100.00% (4/4)
|
||||||
github.com/conformal/btcec/field.go fieldVal.SetHex 100.00% (4/4)
|
github.com/conformal/btcec/field.go fieldVal.SetHex 100.00% (4/4)
|
||||||
github.com/conformal/btcec/signature.go canonicalPadding 100.00% (4/4)
|
github.com/conformal/btcec/signature.go canonicalPadding 100.00% (4/4)
|
||||||
github.com/conformal/btcec/btcec.go KoblitzCurve.bigAffineToField 100.00% (4/4)
|
|
||||||
github.com/conformal/btcec/btcec.go KoblitzCurve.IsOnCurve 100.00% (4/4)
|
github.com/conformal/btcec/btcec.go KoblitzCurve.IsOnCurve 100.00% (4/4)
|
||||||
github.com/conformal/btcec/field.go fieldVal.SetInt 100.00% (3/3)
|
github.com/conformal/btcec/field.go fieldVal.SetInt 100.00% (3/3)
|
||||||
github.com/conformal/btcec/field.go fieldVal.Bytes 100.00% (3/3)
|
github.com/conformal/btcec/field.go fieldVal.Bytes 100.00% (3/3)
|
||||||
|
github.com/conformal/btcec/field.go fieldVal.IsZero 100.00% (2/2)
|
||||||
|
github.com/conformal/btcec/field.go fieldVal.AddInt 100.00% (2/2)
|
||||||
|
github.com/conformal/btcec/field.go fieldVal.Equals 100.00% (2/2)
|
||||||
|
github.com/conformal/btcec/field.go fieldVal.Set 100.00% (2/2)
|
||||||
github.com/conformal/btcec/field.go fieldVal.String 100.00% (2/2)
|
github.com/conformal/btcec/field.go fieldVal.String 100.00% (2/2)
|
||||||
github.com/conformal/btcec/btcec.go S256 100.00% (2/2)
|
github.com/conformal/btcec/btcec.go S256 100.00% (2/2)
|
||||||
github.com/conformal/btcec/field.go fieldVal.IsZero 100.00% (2/2)
|
|
||||||
github.com/conformal/btcec/field.go fieldVal.Equals 100.00% (2/2)
|
|
||||||
github.com/conformal/btcec/field.go fieldVal.AddInt 100.00% (2/2)
|
|
||||||
github.com/conformal/btcec/field.go fieldVal.Set 100.00% (2/2)
|
|
||||||
github.com/conformal/btcec/pubkey.go isOdd 100.00% (1/1)
|
github.com/conformal/btcec/pubkey.go isOdd 100.00% (1/1)
|
||||||
github.com/conformal/btcec/field.go fieldVal.Mul 100.00% (1/1)
|
|
||||||
github.com/conformal/btcec/field.go fieldVal.Square 100.00% (1/1)
|
|
||||||
github.com/conformal/btcec/btcec.go KoblitzCurve.Params 100.00% (1/1)
|
|
||||||
github.com/conformal/btcec/btcec.go KoblitzCurve.ScalarBaseMult 100.00% (1/1)
|
|
||||||
github.com/conformal/btcec/btcec.go KoblitzCurve.QPlus1Div4 100.00% (1/1)
|
|
||||||
github.com/conformal/btcec/btcec.go initAll 100.00% (1/1)
|
|
||||||
github.com/conformal/btcec/field.go fieldVal.Negate 100.00% (1/1)
|
|
||||||
github.com/conformal/btcec/signature.go ParseSignature 100.00% (1/1)
|
|
||||||
github.com/conformal/btcec/signature.go ParseDERSignature 100.00% (1/1)
|
github.com/conformal/btcec/signature.go ParseDERSignature 100.00% (1/1)
|
||||||
|
github.com/conformal/btcec/btcec.go KoblitzCurve.ScalarBaseMult 100.00% (1/1)
|
||||||
|
github.com/conformal/btcec/field.go fieldVal.Mul 100.00% (1/1)
|
||||||
|
github.com/conformal/btcec/btcec.go KoblitzCurve.Params 100.00% (1/1)
|
||||||
|
github.com/conformal/btcec/field.go fieldVal.Square 100.00% (1/1)
|
||||||
|
github.com/conformal/btcec/field.go fieldVal.Negate 100.00% (1/1)
|
||||||
github.com/conformal/btcec/field.go fieldVal.IsOdd 100.00% (1/1)
|
github.com/conformal/btcec/field.go fieldVal.IsOdd 100.00% (1/1)
|
||||||
github.com/conformal/btcec/pubkey.go ParsePubKey 96.88% (31/32)
|
github.com/conformal/btcec/btcec.go initAll 100.00% (1/1)
|
||||||
github.com/conformal/btcec ------------------------------------- 99.88% (846/847)
|
github.com/conformal/btcec/btcec.go KoblitzCurve.QPlus1Div4 100.00% (1/1)
|
||||||
|
github.com/conformal/btcec/signature.go ParseSignature 100.00% (1/1)
|
||||||
|
github.com/conformal/btcec/pubkey.go ParsePubKey 96.15% (25/26)
|
||||||
|
github.com/conformal/btcec/signature.go SignCompact 90.91% (20/22)
|
||||||
|
github.com/conformal/btcec/pubkey.go decompressPoint 88.89% (8/9)
|
||||||
|
github.com/conformal/btcec/signature.go recoverKeyFromSignature 86.96% (20/23)
|
||||||
|
github.com/conformal/btcec/signature.go RecoverCompact 77.78% (7/9)
|
||||||
|
github.com/conformal/btcec/signature.go hashToInt 77.78% (7/9)
|
||||||
|
github.com/conformal/btcec ------------------------------------- 98.80% (903/914)
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue