Skip to content

Instantly share code, notes, and snippets.

@xbee
Forked from kac-/blind_oleg.go
Created November 25, 2016 09:18
Show Gist options
  • Save xbee/93d569d21f9545fbc0e4a5bd5cfa05f3 to your computer and use it in GitHub Desktop.
Save xbee/93d569d21f9545fbc0e4a5bd5cfa05f3 to your computer and use it in GitHub Desktop.
Blind signatures for Bitcoin transactions
package main
import (
"crypto/ecdsa"
"crypto/elliptic"
"crypto/sha256"
"fmt"
"math/big"
)
// author: Oleg Andreev
// Blind signatures for Bitcoin transactions
// Second draft
// http://oleganza.com/blind-ecdsa-draft-v2.pdf
func main() {
type Alice struct {
// message
m *big.Int
// Let a, b, c and d be unique random numbers within [1, n – 1] chosen by Alice.
a, b, c, d *big.Int
}
type Bob struct {
// Let p and q be unique random numbers within [1, n – 1] chosen by Bob.
p, q *big.Int
}
// curve
E := elliptic.P256()
// params
params := E.Params()
n := params.N
alice, bob := Alice{m: big.NewInt(7)}, Bob{}
// 1. Alice chooses random numbers a, b, c, d within [1, n – 1].
alice.a, alice.b, alice.c, alice.d = big.NewInt(11), big.NewInt(13), big.NewInt(17), big.NewInt(19)
// help vars for calcs
tmp, x, y := new(big.Int), new(big.Int), new(big.Int)
// 2. Bob chooses random numbers p, q within [1, n – 1]
// and sends two EC points to Alice: P = (p -1 ·G) and Q = (q·p -1 ·G).
bob.p, bob.q = big.NewInt(23), big.NewInt(29)
Px, Py := E.ScalarBaseMult(new(big.Int).ModInverse(bob.p, n).Bytes())
Qx, Qy := E.ScalarBaseMult(new(big.Int).Mul(bob.q, new(big.Int).ModInverse(bob.p, n)).Bytes())
// 3. Alice computes K = (c·a) -1 ·P and public key T = (a·Kx) -1 ·(b·G + Q + d·c -1 ·P).
// Bob cannot know if his parameters were involved in K or T without the knowledge of a, b, c and d.
// Thus, Alice can safely publish T (e.g. in a Bitcoin transaction that locks funds with T).
tmp = new(big.Int)
Kx, Ky := E.ScalarMult(Px, Py, tmp.Mul(alice.c, alice.a).ModInverse(tmp, n).Bytes())
Tx, Ty := E.ScalarBaseMult(alice.b.Bytes())
Tx, Ty = E.Add(Tx, Ty, Qx, Qy)
x, y = E.ScalarMult(Px, Py, new(big.Int).Mul(alice.d, new(big.Int).ModInverse(alice.c, n)).Bytes())
Tx, Ty = E.Add(Tx, Ty, x, y)
tmp = new(big.Int)
Tx, Ty = E.ScalarMult(Tx, Ty, tmp.Mul(alice.a, Kx).ModInverse(tmp, n).Bytes())
// 4. When time comes to sign a message (e.g. redeeming funds locked in a Bitcoin transaction),
// Alice computes the hash h of her message.
h := hashToInt(hash(alice.m.Bytes()), E)
// 5. Alice blinds the hash and sends h 2 = a·h + b (mod n) to Bob.
tmp = new(big.Int)
h2 := tmp.Mul(alice.a, h).Add(tmp, alice.b).Mod(tmp, n)
// 6. Bob verifies the identity of Alice via separate communications channel.
// 7. Bob signs the blinded hash and returns the signature to Alice: s 1 = p·h 2 + q (mod n).
tmp = new(big.Int)
s1 := tmp.Mul(bob.p, h2).Add(tmp, bob.q).Mod(tmp, n)
// 8. Alice unblinds the signature: s 2 = c·s 1 + d (mod n).
tmp = new(big.Int)
s2 := tmp.Mul(alice.c, s1).Add(tmp, alice.d).Mod(tmp, n)
// 9. Now Alice has (Kx, s 2 ) which is a valid ECDSA signature of hash h verifiable by public key T.
// If she uses it in a Bitcoin transaction, she will be able to redeem her locked funds without Bob
// knowing which transaction he just helped to sign.
// verify with standar ecdsa package
fmt.Println(ecdsa.Verify(&ecdsa.PublicKey{Curve: E, X: Tx, Y: Ty}, h.Bytes(), Kx, s2))
_ = Ky
}
func hash(msg []byte) []byte {
hasher := sha256.New()
hasher.Write(msg)
return hasher.Sum(nil)
}
// from http://golang.org/src/pkg/crypto/ecdsa/ecdsa.go
// 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.
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
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment