package ecdsa
import (
"crypto/elliptic"
"errors"
"io"
"math/big"
"golang.org/x/crypto/cryptobyte"
"golang.org/x/crypto/cryptobyte/asn1"
)
func generateLegacy (c elliptic .Curve , rand io .Reader ) (*PrivateKey , error ) {
k , err := randFieldElement (c , rand )
if err != nil {
return nil , err
}
priv := new (PrivateKey )
priv .PublicKey .Curve = c
priv .D = k
priv .PublicKey .X , priv .PublicKey .Y = c .ScalarBaseMult (k .Bytes ())
return priv , nil
}
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
}
var errZeroParam = errors .New ("zero parameter" )
func Sign (rand io .Reader , priv *PrivateKey , hash []byte ) (r , s *big .Int , err error ) {
sig , err := SignASN1 (rand , priv , hash )
if err != nil {
return nil , nil , err
}
r , s = new (big .Int ), new (big .Int )
var inner cryptobyte .String
input := cryptobyte .String (sig )
if !input .ReadASN1 (&inner , asn1 .SEQUENCE ) ||
!input .Empty () ||
!inner .ReadASN1Integer (r ) ||
!inner .ReadASN1Integer (s ) ||
!inner .Empty () {
return nil , nil , errors .New ("invalid ASN.1 from SignASN1" )
}
return r , s , nil
}
func signLegacy (priv *PrivateKey , csprng io .Reader , hash []byte ) (sig []byte , err error ) {
c := priv .Curve
N := c .Params ().N
if N .Sign () == 0 {
return nil , errZeroParam
}
var k , kInv , r , s *big .Int
for {
for {
k , err = randFieldElement (c , csprng )
if err != nil {
return nil , err
}
kInv = new (big .Int ).ModInverse (k , N )
r , _ = c .ScalarBaseMult (k .Bytes ())
r .Mod (r , N )
if r .Sign () != 0 {
break
}
}
e := hashToInt (hash , c )
s = new (big .Int ).Mul (priv .D , r )
s .Add (s , e )
s .Mul (s , kInv )
s .Mod (s , N )
if s .Sign () != 0 {
break
}
}
return encodeSignature (r .Bytes (), s .Bytes ())
}
func Verify (pub *PublicKey , hash []byte , r , s *big .Int ) bool {
if r .Sign () <= 0 || s .Sign () <= 0 {
return false
}
sig , err := encodeSignature (r .Bytes (), s .Bytes ())
if err != nil {
return false
}
return VerifyASN1 (pub , hash , sig )
}
func verifyLegacy (pub *PublicKey , hash []byte , sig []byte ) bool {
rBytes , sBytes , err := parseSignature (sig )
if err != nil {
return false
}
r , s := new (big .Int ).SetBytes (rBytes ), new (big .Int ).SetBytes (sBytes )
c := pub .Curve
N := c .Params ().N
if r .Sign () <= 0 || s .Sign () <= 0 {
return false
}
if r .Cmp (N ) >= 0 || s .Cmp (N ) >= 0 {
return false
}
e := hashToInt (hash , c )
w := new (big .Int ).ModInverse (s , N )
u1 := e .Mul (e , w )
u1 .Mod (u1 , N )
u2 := w .Mul (r , w )
u2 .Mod (u2 , N )
x1 , y1 := c .ScalarBaseMult (u1 .Bytes ())
x2 , y2 := c .ScalarMult (pub .X , pub .Y , u2 .Bytes ())
x , y := c .Add (x1 , y1 , x2 , y2 )
if x .Sign () == 0 && y .Sign () == 0 {
return false
}
x .Mod (x , N )
return x .Cmp (r ) == 0
}
var one = new (big .Int ).SetInt64 (1 )
func randFieldElement (c elliptic .Curve , rand io .Reader ) (k *big .Int , err error ) {
for {
N := c .Params ().N
b := make ([]byte , (N .BitLen ()+7 )/8 )
if _, err = io .ReadFull (rand , b ); err != nil {
return
}
if excess := len (b )*8 - N .BitLen (); excess > 0 {
b [0 ] >>= excess
}
k = new (big .Int ).SetBytes (b )
if k .Sign () != 0 && k .Cmp (N ) < 0 {
return
}
}
}
The pages are generated with Golds v0.6.7 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @Go100and1 (reachable from the left QR code) to get the latest news of Golds .