ECDSA 和 ed25519

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())
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,589评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,615评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,933评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,976评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,999评论 6 393
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,775评论 1 307
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,474评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,359评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,854评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,007评论 3 338
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,146评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,826评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,484评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,029评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,153评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,420评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,107评论 2 356

推荐阅读更多精彩内容