commit e892dadfb1760893ed2ae8d007b68f33d9d57d8e
parent 87142f1fb37f283ac414f106ae472570a1b81a9d
Author: n0tr1v <n0tr1v@protonmail.com>
Date: Sun, 29 Jan 2023 17:48:15 -0800
rename onion_sign to torsign
Diffstat:
| D | cmd/onion_signer/main.go | | | 208 | ------------------------------------------------------------------------------- |
| A | cmd/torsign/main.go | | | 205 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
2 files changed, 205 insertions(+), 208 deletions(-)
diff --git a/cmd/onion_signer/main.go b/cmd/onion_signer/main.go
@@ -1,208 +0,0 @@
-package main
-
-import (
- "bytes"
- "crypto/ed25519"
- "crypto/sha512"
- "encoding/base32"
- "encoding/pem"
- "flag"
- "fmt"
- "golang.org/x/crypto/sha3"
- "math/big"
- "os"
- "strings"
-)
-
-func main() {
- var privKeyFile string
- flag.StringVar(&privKeyFile, "s", "hs_ed25519_secret_key", "tor private key file")
- flag.Parse()
- fileName := os.Args[1]
- msg, err := os.ReadFile(fileName)
- if err != nil {
- panic(err)
- }
- pemKeyBytes, _ := os.ReadFile(privKeyFile)
- identityPrivKey := loadTorKeyFromDisk(pemKeyBytes)
- identityPubKey := publickeyFromESK(identityPrivKey)
- fmt.Println("Onion address: ", addressFromIdentityKey(identityPubKey))
- signature := sign(identityPrivKey, msg)
- pemSignature := string(pem.EncodeToMemory(&pem.Block{Type: "SIGNATURE", Bytes: signature}))
- fmt.Println(pemSignature)
-}
-
-func loadTorKeyFromDisk(keyBytes []byte) ed25519.PrivateKey {
- if !bytes.Equal(keyBytes[:29], []byte("== ed25519v1-secret: type0 ==")) {
- panic("Tor key does not start with Tor header")
- }
- expandedSk := keyBytes[32:]
- if len(expandedSk) != 64 {
- panic("Tor private key has the wrong length")
- }
- return expandedSk
-}
-
-func sign(identityPrivKey, msg []byte) []byte {
- return signatureWithESK(msg, identityPrivKey, publickeyFromESK(identityPrivKey))
-}
-
-func addressFromIdentityKey(pub ed25519.PublicKey) string {
- var checksumBytes bytes.Buffer
- checksumBytes.Write([]byte(".onion checksum"))
- checksumBytes.Write(pub)
- checksumBytes.Write([]byte{0x03})
- checksum := sha3.Sum256(checksumBytes.Bytes())
- var onionAddressBytes bytes.Buffer
- onionAddressBytes.Write(pub)
- onionAddressBytes.Write(checksum[:2])
- onionAddressBytes.Write([]byte{0x03})
- addr := strings.ToLower(base32.StdEncoding.EncodeToString(onionAddressBytes.Bytes()))
- return addr + ".onion"
-}
-
-var (
- b = 256
- l = biAdd(biExp(bi(2), bi(252)), biFromStr("27742317777372353535851937790883648493"))
- by = biMul(bi(4), inv(bi(5)))
- bx = xrecover(by)
- q = biSub(biExp(bi(2), bi(255)), bi(19))
- bB = []*big.Int{biMod(bx, q), biMod(by, q)}
- I = expmod(bi(2), biDiv(biSub(q, bi(1)), bi(4)), q)
- d = bi(0).Mul(bi(-121665), inv(bi(121666)))
-)
-
-func publickeyFromESK(h []byte) ed25519.PublicKey {
- a := decodeInt(h[:32])
- A := scalarmult(bB, a)
- return encodepoint(A)
-}
-
-func signatureWithESK(msg, blindedEsk, blindedKey []byte) []byte {
- a := decodeInt(blindedEsk[:32])
- lines := make([][]byte, 0)
- for i := b / 8; i < b/4; i++ {
- lines = append(lines, blindedEsk[i:i+1])
- }
- toHint := append(bytes.Join(lines, []byte("")), msg...)
- r := hint(toHint)
- R := scalarmult(bB, r)
- S := biMod(biAdd(r, biMul(hint([]byte(string(encodepoint(R))+string(blindedKey)+string(msg))), a)), l)
- return append(encodepoint(R), encodeint(S)...)
-}
-
-func edwards(P, Q []*big.Int) []*big.Int {
- x1, y1 := P[0], P[1]
- x2, y2 := Q[0], Q[1]
- x3 := biMul(biAdd(biMul(x1, y2), biMul(x2, y1)), inv(biAdd(bi(1), biMul(biMul(biMul(biMul(d, x1), x2), y1), y2))))
- y3 := biMul(biAdd(biMul(y1, y2), biMul(x1, x2)), inv(biSub(bi(1), biMul(biMul(biMul(biMul(d, x1), x2), y1), y2))))
- return []*big.Int{biMod(x3, q), biMod(y3, q)}
-}
-
-func scalarmult(P []*big.Int, e *big.Int) []*big.Int {
- if e.Cmp(bi(0)) == 0 {
- return []*big.Int{bi(0), bi(1)}
- }
- Q := scalarmult(P, biDiv(e, bi(2)))
- Q = edwards(Q, Q)
- if biAnd(e, bi(1)).Int64() == 1 {
- Q = edwards(Q, P)
- }
- return Q
-}
-
-func encodepoint(P []*big.Int) []byte {
- x, y := P[0], P[1]
- bits := make([]uint8, 0)
- for i := 0; i < b-1; i++ {
- bits = append(bits, uint8(biAnd(biRsh(y, uint(i)), bi(1)).Int64()))
- }
- bits = append(bits, uint8(biAnd(x, bi(1)).Int64()))
- by := make([]uint8, 0)
- for i := 0; i < b/8; i++ {
- sum := uint8(0)
- for j := 0; j < 8; j++ {
- sum += bits[i*8+j] << j
- }
- by = append(by, sum)
- }
- return by
-}
-
-func hint(m []byte) *big.Int {
- tmp := sha512.Sum512(m)
- h := tmp[:]
- sum := bi(0)
- for i := 0; i < 2*b; i++ {
- sum = biAdd(sum, biMul(biExp(bi(2), bi(int64(i))), bi(int64(Bit(h, int64(i))))))
- }
- return sum
-}
-
-func encodeint(y *big.Int) []byte {
- bits := make([]*big.Int, 0)
- for i := 0; i < b; i++ {
- bits = append(bits, biAnd(biRsh(y, uint(i)), bi(1)))
- }
- final := make([]byte, 0)
- for i := 0; i < b/8; i++ {
- sum := bi(0)
- for j := 0; j < 8; j++ {
- sum = biAdd(sum, biLsh(bits[i*8+j], uint(j)))
- }
- final = append(final, byte(sum.Uint64()))
- }
- return final
-}
-
-func decodeInt(s []uint8) *big.Int {
- sum := bi(0)
- for i := 0; i < b; i++ {
- e := biExp(bi(2), bi(int64(i)))
- m := bi(int64(Bit(s, int64(i))))
- sum = sum.Add(sum, biMul(e, m))
- }
- return sum
-}
-
-func xrecover(y *big.Int) *big.Int {
- xx := biMul(biSub(biMul(y, y), bi(1)), inv(biAdd(biMul(biMul(d, y), y), bi(1))))
- x := expmod(xx, biDiv(biAdd(q, bi(3)), bi(8)), q)
- if biMod(biSub(biMul(x, x), xx), q).Int64() != 0 {
- x = biMod(biMul(x, I), q)
- }
- if biMod(x, bi(2)).Int64() != 0 {
- x = biSub(q, x)
- }
- return x
-}
-
-func expmod(b, e, m *big.Int) *big.Int {
- if e.Cmp(bi(0)) == 0 {
- return bi(1)
- }
- t := biMod(biExp(expmod(b, biDiv(e, bi(2)), m), bi(2)), m)
- if biAnd(e, bi(1)).Int64() == 1 {
- t = biMod(biMul(t, b), m)
- }
- return t
-}
-
-func biFromStr(v string) (out *big.Int) {
- out = new(big.Int)
- _, _ = fmt.Sscan(v, out)
- return
-}
-
-func inv(x *big.Int) *big.Int { return expmod(x, biSub(q, bi(2)), q) }
-func Bit(h []uint8, i int64) uint8 { return (h[i/8] >> (i % 8)) & 1 }
-func bi(v int64) *big.Int { return big.NewInt(v) }
-func biAdd(a, b *big.Int) *big.Int { return bi(0).Add(a, b) }
-func biSub(a, b *big.Int) *big.Int { return bi(0).Sub(a, b) }
-func biMul(a, b *big.Int) *big.Int { return bi(0).Mul(a, b) }
-func biDiv(a, b *big.Int) *big.Int { return bi(0).Div(a, b) }
-func biAnd(a, b *big.Int) *big.Int { return bi(0).And(a, b) }
-func biMod(a, b *big.Int) *big.Int { return bi(0).Mod(a, b) }
-func biExp(a, b *big.Int) *big.Int { return bi(0).Exp(a, b, nil) }
-func biLsh(a *big.Int, b uint) *big.Int { return bi(0).Lsh(a, b) }
-func biRsh(a *big.Int, b uint) *big.Int { return bi(0).Rsh(a, b) }
diff --git a/cmd/torsign/main.go b/cmd/torsign/main.go
@@ -0,0 +1,205 @@
+package main
+
+import (
+ "bytes"
+ "crypto/ed25519"
+ "crypto/sha512"
+ "encoding/base32"
+ "encoding/base64"
+ "flag"
+ "fmt"
+ "golang.org/x/crypto/sha3"
+ "math/big"
+ "os"
+ "strings"
+)
+
+func main() {
+ var privKeyFile string
+ flag.StringVar(&privKeyFile, "s", "hs_ed25519_secret_key", "tor private key file")
+ flag.Parse()
+ fileName := os.Args[1]
+ msg, err := os.ReadFile(fileName)
+ if err != nil {
+ panic(err)
+ }
+ pemKeyBytes, _ := os.ReadFile(privKeyFile)
+ identityPrivKey := loadTorKeyFromDisk(pemKeyBytes)
+ signature := sign(identityPrivKey, msg)
+ fmt.Println(base64.StdEncoding.EncodeToString(signature))
+}
+
+func loadTorKeyFromDisk(keyBytes []byte) ed25519.PrivateKey {
+ if !bytes.Equal(keyBytes[:29], []byte("== ed25519v1-secret: type0 ==")) {
+ panic("Tor key does not start with Tor header")
+ }
+ expandedSk := keyBytes[32:]
+ if len(expandedSk) != 64 {
+ panic("Tor private key has the wrong length")
+ }
+ return expandedSk
+}
+
+func sign(identityPrivKey, msg []byte) []byte {
+ return signatureWithESK(msg, identityPrivKey, publickeyFromESK(identityPrivKey))
+}
+
+func addressFromIdentityKey(pub ed25519.PublicKey) string {
+ var checksumBytes bytes.Buffer
+ checksumBytes.Write([]byte(".onion checksum"))
+ checksumBytes.Write(pub)
+ checksumBytes.Write([]byte{0x03})
+ checksum := sha3.Sum256(checksumBytes.Bytes())
+ var onionAddressBytes bytes.Buffer
+ onionAddressBytes.Write(pub)
+ onionAddressBytes.Write(checksum[:2])
+ onionAddressBytes.Write([]byte{0x03})
+ addr := strings.ToLower(base32.StdEncoding.EncodeToString(onionAddressBytes.Bytes()))
+ return addr + ".onion"
+}
+
+var (
+ b = 256
+ l = biAdd(biExp(bi(2), bi(252)), biFromStr("27742317777372353535851937790883648493"))
+ by = biMul(bi(4), inv(bi(5)))
+ bx = xrecover(by)
+ q = biSub(biExp(bi(2), bi(255)), bi(19))
+ bB = []*big.Int{biMod(bx, q), biMod(by, q)}
+ I = expmod(bi(2), biDiv(biSub(q, bi(1)), bi(4)), q)
+ d = bi(0).Mul(bi(-121665), inv(bi(121666)))
+)
+
+func publickeyFromESK(h []byte) ed25519.PublicKey {
+ a := decodeInt(h[:32])
+ A := scalarmult(bB, a)
+ return encodepoint(A)
+}
+
+func signatureWithESK(msg, blindedEsk, blindedKey []byte) []byte {
+ a := decodeInt(blindedEsk[:32])
+ lines := make([][]byte, 0)
+ for i := b / 8; i < b/4; i++ {
+ lines = append(lines, blindedEsk[i:i+1])
+ }
+ toHint := append(bytes.Join(lines, []byte("")), msg...)
+ r := hint(toHint)
+ R := scalarmult(bB, r)
+ S := biMod(biAdd(r, biMul(hint([]byte(string(encodepoint(R))+string(blindedKey)+string(msg))), a)), l)
+ return append(encodepoint(R), encodeint(S)...)
+}
+
+func edwards(P, Q []*big.Int) []*big.Int {
+ x1, y1 := P[0], P[1]
+ x2, y2 := Q[0], Q[1]
+ x3 := biMul(biAdd(biMul(x1, y2), biMul(x2, y1)), inv(biAdd(bi(1), biMul(biMul(biMul(biMul(d, x1), x2), y1), y2))))
+ y3 := biMul(biAdd(biMul(y1, y2), biMul(x1, x2)), inv(biSub(bi(1), biMul(biMul(biMul(biMul(d, x1), x2), y1), y2))))
+ return []*big.Int{biMod(x3, q), biMod(y3, q)}
+}
+
+func scalarmult(P []*big.Int, e *big.Int) []*big.Int {
+ if e.Cmp(bi(0)) == 0 {
+ return []*big.Int{bi(0), bi(1)}
+ }
+ Q := scalarmult(P, biDiv(e, bi(2)))
+ Q = edwards(Q, Q)
+ if biAnd(e, bi(1)).Int64() == 1 {
+ Q = edwards(Q, P)
+ }
+ return Q
+}
+
+func encodepoint(P []*big.Int) []byte {
+ x, y := P[0], P[1]
+ bits := make([]uint8, 0)
+ for i := 0; i < b-1; i++ {
+ bits = append(bits, uint8(biAnd(biRsh(y, uint(i)), bi(1)).Int64()))
+ }
+ bits = append(bits, uint8(biAnd(x, bi(1)).Int64()))
+ by := make([]uint8, 0)
+ for i := 0; i < b/8; i++ {
+ sum := uint8(0)
+ for j := 0; j < 8; j++ {
+ sum += bits[i*8+j] << j
+ }
+ by = append(by, sum)
+ }
+ return by
+}
+
+func hint(m []byte) *big.Int {
+ tmp := sha512.Sum512(m)
+ h := tmp[:]
+ sum := bi(0)
+ for i := 0; i < 2*b; i++ {
+ sum = biAdd(sum, biMul(biExp(bi(2), bi(int64(i))), bi(int64(Bit(h, int64(i))))))
+ }
+ return sum
+}
+
+func encodeint(y *big.Int) []byte {
+ bits := make([]*big.Int, 0)
+ for i := 0; i < b; i++ {
+ bits = append(bits, biAnd(biRsh(y, uint(i)), bi(1)))
+ }
+ final := make([]byte, 0)
+ for i := 0; i < b/8; i++ {
+ sum := bi(0)
+ for j := 0; j < 8; j++ {
+ sum = biAdd(sum, biLsh(bits[i*8+j], uint(j)))
+ }
+ final = append(final, byte(sum.Uint64()))
+ }
+ return final
+}
+
+func decodeInt(s []uint8) *big.Int {
+ sum := bi(0)
+ for i := 0; i < b; i++ {
+ e := biExp(bi(2), bi(int64(i)))
+ m := bi(int64(Bit(s, int64(i))))
+ sum = sum.Add(sum, biMul(e, m))
+ }
+ return sum
+}
+
+func xrecover(y *big.Int) *big.Int {
+ xx := biMul(biSub(biMul(y, y), bi(1)), inv(biAdd(biMul(biMul(d, y), y), bi(1))))
+ x := expmod(xx, biDiv(biAdd(q, bi(3)), bi(8)), q)
+ if biMod(biSub(biMul(x, x), xx), q).Int64() != 0 {
+ x = biMod(biMul(x, I), q)
+ }
+ if biMod(x, bi(2)).Int64() != 0 {
+ x = biSub(q, x)
+ }
+ return x
+}
+
+func expmod(b, e, m *big.Int) *big.Int {
+ if e.Cmp(bi(0)) == 0 {
+ return bi(1)
+ }
+ t := biMod(biExp(expmod(b, biDiv(e, bi(2)), m), bi(2)), m)
+ if biAnd(e, bi(1)).Int64() == 1 {
+ t = biMod(biMul(t, b), m)
+ }
+ return t
+}
+
+func biFromStr(v string) (out *big.Int) {
+ out = new(big.Int)
+ _, _ = fmt.Sscan(v, out)
+ return
+}
+
+func inv(x *big.Int) *big.Int { return expmod(x, biSub(q, bi(2)), q) }
+func Bit(h []uint8, i int64) uint8 { return (h[i/8] >> (i % 8)) & 1 }
+func bi(v int64) *big.Int { return big.NewInt(v) }
+func biAdd(a, b *big.Int) *big.Int { return bi(0).Add(a, b) }
+func biSub(a, b *big.Int) *big.Int { return bi(0).Sub(a, b) }
+func biMul(a, b *big.Int) *big.Int { return bi(0).Mul(a, b) }
+func biDiv(a, b *big.Int) *big.Int { return bi(0).Div(a, b) }
+func biAnd(a, b *big.Int) *big.Int { return bi(0).And(a, b) }
+func biMod(a, b *big.Int) *big.Int { return bi(0).Mod(a, b) }
+func biExp(a, b *big.Int) *big.Int { return bi(0).Exp(a, b, nil) }
+func biLsh(a *big.Int, b uint) *big.Int { return bi(0).Lsh(a, b) }
+func biRsh(a *big.Int, b uint) *big.Int { return bi(0).Rsh(a, b) }