case p384:
return 2, 48, true
case p521:
+ // Note that the block size doesn't match the field size for P-521.
return 3, 80, true
}
return 0, 0, false // A mismatch
}
-func hashToBytes[P Point[P]](c *Curve[P], dst, hash []byte) {
+func hashToBytes[P Point[P]](c *Curve[P], hash []byte) []byte {
e := bigmod.NewNat()
hashToNat(c, e, hash)
- copy(dst, e.Bytes(c.N))
+ return e.Bytes(c.N)
+}
+
+func appendBlock(p []byte, blocksize int, b []byte) []byte {
+ if len(b) > blocksize {
+ panic("ecdsa: internal error: appendBlock input larger than block")
+ }
+ padding := blocksize - len(b)
+ p = append(p, make([]byte, padding)...)
+ return append(p, b...)
+}
+
+func trimBlock(p []byte, size int) ([]byte, error) {
+ for _, b := range p[:len(p)-size] {
+ if b != 0 {
+ return nil, errors.New("ecdsa: internal error: KDSA produced invalid signature")
+ }
+ }
+ return p[len(p)-size:], nil
}
func sign[P Point[P]](c *Curve[P], priv *PrivateKey, drbg *hmacDRBG, hash []byte) (*Signature, error) {
// Copy content into the parameter block. In the sign case,
// we copy hashed message, private key and random number into
- // the parameter block.
- hashToBytes(c, params[2*blockSize:3*blockSize], hash)
- copy(params[3*blockSize+blockSize-len(priv.d):], priv.d)
- copy(params[4*blockSize:5*blockSize], k.Bytes(c.N))
+ // the parameter block. We skip the signature slots.
+ p := params[:2*blockSize]
+ p = appendBlock(p, blockSize, hashToBytes(c, hash))
+ p = appendBlock(p, blockSize, priv.d)
+ p = appendBlock(p, blockSize, k.Bytes(c.N))
// Convert verify function code into a sign function code by adding 8.
// We also need to set the 'deterministic' bit in the function code, by
// adding 128, in order to stop the instruction using its own random number
// generator in addition to the random number we supply.
switch kdsa(functionCode+136, ¶ms) {
case 0: // success
- return &Signature{R: params[:blockSize], S: params[blockSize : 2*blockSize]}, nil
+ elementSize := (c.N.BitLen() + 7) / 8
+ r, err := trimBlock(params[:blockSize], elementSize)
+ if err != nil {
+ return nil, err
+ }
+ s, err := trimBlock(params[blockSize:2*blockSize], elementSize)
+ if err != nil {
+ return nil, err
+ }
+ return &Signature{R: r, S: s}, nil
case 1: // error
return nil, errors.New("zero parameter")
case 2: // retry
// Copy content into the parameter block. In the verify case,
// we copy signature (r), signature(s), hashed message, public key x component,
// and public key y component into the parameter block.
- copy(params[0*blockSize+blockSize-len(r):], r)
- copy(params[1*blockSize+blockSize-len(s):], s)
- hashToBytes(c, params[2*blockSize:3*blockSize], hash)
- copy(params[3*blockSize:5*blockSize], pub.q[1:]) // strip 0x04 prefix
+ p := params[:0]
+ p = appendBlock(p, blockSize, r)
+ p = appendBlock(p, blockSize, s)
+ p = appendBlock(p, blockSize, hashToBytes(c, hash))
+ p = appendBlock(p, blockSize, pub.q[1:1+len(pub.q)/2])
+ p = appendBlock(p, blockSize, pub.q[1+len(pub.q)/2:])
if kdsa(functionCode, ¶ms) != 0 {
return errors.New("invalid signature")
}