image.png
Speck256k1 签名
20241106-210707.jpeg
Schnoor 签名
image.png
ECDSA
r = k * G的x坐标, (k是随机数)
s = (H(m) + d * r) * k^−1 mod n,其中(H(m) 是消息 m 的哈希值,k^−1是 k 的模 n 的乘法逆元。
签名结果是 r,s
func sign(privateKey *PrivateKey, hash []byte,nonce int) (*Signature, error) {
// - 椭圆曲线的阶
N := S256().N
halfOrder := S256().halfOrder
// - 随机数 k
k := nonceRFC6979(privkey.D, hash,nonce)
// - k^-1
inv := new(big.Int).ModInverse(k, N)
// - k*G = R, r为椭圆曲线上R的x坐标
r, _ := privkey.Curve.ScalarBaseMult(k.Bytes())
if r.Cmp(N) == 1 {
r.Sub(r, N)
}
if r.Sign() == 0 {
return nil, errors.New("calculated R is zero")
}
// - prvKey * r
e := hashToInt(hash, privkey.Curve)
s := new(big.Int).Mul(privkey.D, r)
// - prvKey * r + e
s.Add(s, e)
// - (prvKey * r + e) * k^-1
s.Mul(s, inv)
// - ((prvKey * r + e) * k^-1) mod n
s.Mod(s, N)
if s.Cmp(halfOrder) == 1 {
s.Sub(N, s)
}
if s.Sign() == 0 {
return nil, errors.New("calculated S is zero")
}
return &Signature{R: r, S: s}, nil
}
func verify(pub *PublicKey, hash []byte, sig []byte) bool {
// - 解析 r,s
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
}
// - 将c转成整数
e := hashToInt(hash, c)
// - s^-1
w := new(big.Int).ModInverse(s, N)
// - e * s^-1
u1 := e.Mul(e, w)
u1.Mod(u1, N)
// - r * s^-1
u2 := w.Mul(r, w)
u2.Mod(u2, N)
// - u1*G, u1在椭圆曲线上的点
x1, y1 := c.ScalarBaseMult(u1.Bytes())
// - u2*pub = u2(pub.x, pub.y)
x2, y2 := c.ScalarMult(pub.X, pub.Y, u2.Bytes())
// - x1+x2, y1+y2
/* e * s^-1 * G + r * s^-1 * pub
= e * s^-1 * G + r * s^-1 *(prv * G)
= (e + r *prv)*s^-1 * G
= k*G
k*G 表示点k在椭圆曲线上的坐标, 即签名时候的R, 所以,如果 (k*G).x 为签名信息中的 r;
*/
x, y := c.Add(x1, y1, x2, y2)
if x.Sign() == 0 && y.Sign() == 0 {
return false
}
x.Mod(x, N)
// - s == r, 验证成功
return x.Cmp(r) == 0
}
image.png
ed25519
R=r×G (r是随机数)
s = r + H(R,A,m) * k mod l H(R,A,m) 是将点 R、公钥A 和消息哈希 H(m) 连接起来并哈希得到的值,
l 是 edwards25519 曲线的阶数。
func sign(signature, privateKey, message []byte, domPrefix, context string) {
if l := len(privateKey); l != PrivateKeySize {
panic("ed25519: bad private key length: " + strconv.Itoa(l))
}
// - 加工原私钥(这里的原私钥不是导入的字符串私钥, 而是经过处理的原私钥, 即ed25519.NewKeyFromSeed(util.GetRawKeySeed(c.PrvKey.D)) 的结果 而 c.PrvKey.D的计算是 ), 得到签名使用的私钥 s
seed, publicKey := privateKey[:SeedSize], privateKey[SeedSize:]
h := sha512.Sum512(seed)
s, err := edwards25519.NewScalar().SetBytesWithClamping(h[:32])
if err != nil {
panic("ed25519: internal error: setting scalar failed")
}
// - 生成随机数 r
prefix := h[32:]
mh := sha512.New()
if domPrefix != domPrefixPure {
mh.Write([]byte(domPrefix))
mh.Write([]byte{byte(len(context))})
mh.Write([]byte(context))
}
mh.Write(prefix)
mh.Write(message)
messageDigest := make([]byte, 0, sha512.Size)
messageDigest = mh.Sum(messageDigest)
r, err := edwards25519.NewScalar().SetUniformBytes(messageDigest)
if err != nil {
panic("ed25519: internal error: setting scalar failed")
}
// - 随机数 r 在椭圆曲线上的点 R
R := (&edwards25519.Point{}).ScalarBaseMult(r)
// - 将点 R、公钥A 和消息哈希 H(m) 连接起来并哈希得到的值
kh := sha512.New()
if domPrefix != domPrefixPure {
kh.Write([]byte(domPrefix))
kh.Write([]byte{byte(len(context))})
kh.Write([]byte(context))
}
kh.Write(R.Bytes())
kh.Write(publicKey)
kh.Write(message)
hramDigest := make([]byte, 0, sha512.Size)
hramDigest = kh.Sum(hramDigest)
k, err := edwards25519.NewScalar().SetUniformBytes(hramDigest)
if err != nil {
panic("ed25519: internal error: setting scalar failed")
}
// - S = r + H(R,A,m) * k mod l, 代码中的k是 H(R,A,m) , s 是私钥. r 是 随机数
S := edwards25519.NewScalar().MultiplyAdd(k, s, r)
copy(signature[:32], R.Bytes())
copy(signature[32:], S.Bytes())
}
func verify(publicKey PublicKey, message, sig []byte, domPrefix, context string) bool {
if l := len(publicKey); l != PublicKeySize {
panic("ed25519: bad public key length: " + strconv.Itoa(l))
}
if len(sig) != SignatureSize || sig[63]&224 != 0 {
return false
}
// - A 公钥在椭圆曲线的坐标
A, err := (&edwards25519.Point{}).SetBytes(publicKey)
if err != nil {
return false
}
// - 将点 R、公钥A 和消息哈希 H(m) 连接起来并哈希得到的值
kh := sha512.New()
if domPrefix != domPrefixPure {
kh.Write([]byte(domPrefix))
kh.Write([]byte{byte(len(context))})
kh.Write([]byte(context))
}
kh.Write(sig[:32])
kh.Write(publicKey)
kh.Write(message)
hramDigest := make([]byte, 0, sha512.Size)
hramDigest = kh.Sum(hramDigest)
k, err := edwards25519.NewScalar().SetUniformBytes(hramDigest)
if err != nil {
panic("ed25519: internal error: setting scalar failed")
}
// - S的字节数组转成整数
S, err := edwards25519.NewScalar().SetCanonicalBytes(sig[32:])
if err != nil {
return false
}
// [S]B = R + [k]A --> [k](-A) + [S]B = R
minusA := (&edwards25519.Point{}).Negate(A)
R := (&edwards25519.Point{}).VarTimeDoubleScalarBaseMult(k, minusA, S)
// - R相等表示验证通过
return bytes.Equal(sig[:32], R.Bytes())
}
image.png
ed25519的公私钥生成流程
ed25519 生成的是一个种子, 使用这个种子生成公钥, 私钥, 地址
// - 1. 取导入的私钥的前32字节
func GetRawKeySeed(D *big.Int) []byte {
maxLen:=32
srcBytes:= D.Bytes()
srcLen := len(srcBytes)
if srcLen >= maxLen {
return srcBytes
}
dest := make([]byte, maxLen)
copy(dest[maxLen-srcLen:], srcBytes)
return dest
}
// - 2 计算前32字节的sha512, 并只取结果的前32字节然后修剪作为私钥
func NewKeyFromSeed(seed []byte) PrivateKey {
// Outline the function body so that the returned key can be stack-allocated.
privateKey := make([]byte, PrivateKeySize)
newKeyFromSeed(privateKey, seed)
return privateKey
}
func newKeyFromSeed(privateKey, seed []byte) {
if l := len(seed); l != SeedSize {
panic("ed25519: bad seed length: " + strconv.Itoa(l))
}
// - 私钥
h := sha512.Sum512(seed)
s, err := edwards25519.NewScalar().SetBytesWithClamping(h[:32])
if err != nil {
panic("ed25519: internal error: setting scalar failed")
}
A := (&edwards25519.Point{}).ScalarBaseMult(s)
// - 公钥
publicKey := A.Bytes()
copy(privateKey, seed)
copy(privateKey[32:], publicKey)
}
/* 1. 取导入的私钥的前32字节
2.计算前32字节的sha512, 并只取结果的前32字节然后修剪作为私钥
公钥 : 私钥在椭圆曲线上的点
地址 : 公钥的base58
*/
prvKey := ed25519.NewKeyFromSeed(util.GetRawKeySeed(c.PrvKey.D))
// - 解析输入字符串的私钥转成 prvKey.D
func (priv PrivateKey) Seed() []byte {
return bytes.Clone(priv[:32])
}
func ParseWifOrHexForPrivateKey(key string) (prvKey *btcec.PrivateKey) {
b, err := base58.Decode(key)
priKey := ed25519.PrivateKey(key)
ac := Account{
PublicKey: common.PublicKeyFromBytes(priKey.Public().(ed25519.PublicKey)),
PrivateKey: priKey,
}
prvKey.D = new(big.Int).SetBytes(ac.PrivateKey.Seed())
}