commit 87142f1fb37f283ac414f106ae472570a1b81a9d
parent a879a6e6c101872e5185d9d99a8e8df932effaa6
Author: n0tr1v <n0tr1v@protonmail.com>
Date: Sun, 29 Jan 2023 13:17:25 -0800
cleanup
Diffstat:
1 file changed, 83 insertions(+), 228 deletions(-)
diff --git a/cmd/onion_signer/main.go b/cmd/onion_signer/main.go
@@ -6,6 +6,7 @@ import (
"crypto/sha512"
"encoding/base32"
"encoding/pem"
+ "flag"
"fmt"
"golang.org/x/crypto/sha3"
"math/big"
@@ -14,61 +15,67 @@ import (
)
func main() {
- onionAddress := "your_onion_addr.onion"
- pkPath := "/path/to/hs_ed25519_secret_key"
- msg := []byte("message by n0tr1v")
-
- // Generate signature
- pemKeyBytes, _ := os.ReadFile(pkPath)
- identityPrivKey := LoadTorKeyFromDisk(pemKeyBytes)
- identityPubKey := PublickeyFromESK(identityPrivKey)
- fmt.Println("Onion address: ", AddressFromIdentityKey(identityPubKey))
+ 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)
+}
- // Verify signature
- block, _ := pem.Decode([]byte(pemSignature))
- if block == nil {
- panic("failed to extract 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")
}
- sig := block.Bytes
- pub := identityKeyFromAddress(onionAddress)
- isValid := ed25519.Verify(pub, msg, sig)
- if !isValid {
- panic("invalid signature")
+ expandedSk := keyBytes[32:]
+ if len(expandedSk) != 64 {
+ panic("Tor private key has the wrong length")
}
- fmt.Println("signature is valid")
+ return expandedSk
}
-var (
- bB1 = []*big.Int{biMod(bx, q), biMod(by, q), bi(1), biMod(biMul(bx, by), q)}
- l = biAdd(biExp(bi(2), bi(252)), biFromStr("27742317777372353535851937790883648493"))
- b = 256
- 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)))
- d1 = biMod(biMul(bi(-121665), inv(bi(121666))), q)
-)
-
-func identityKeyFromAddress(onionAddr string) ed25519.PublicKey {
- trimmedAddr := strings.TrimSuffix(onionAddr, ".onion")
- upperAddr := strings.ToUpper(trimmedAddr)
- decodedAddr, _ := base32.StdEncoding.DecodeString(upperAddr)
- return decodedAddr[:32]
+func sign(identityPrivKey, msg []byte) []byte {
+ return signatureWithESK(msg, identityPrivKey, publickeyFromESK(identityPrivKey))
}
-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"
}
-func biFromStr(v string) (out *big.Int) {
- out = new(big.Int)
- _, _ = fmt.Sscan(v, out)
- return
+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 {
@@ -79,79 +86,33 @@ func signatureWithESK(msg, blindedEsk, blindedKey []byte) []byte {
}
toHint := append(bytes.Join(lines, []byte("")), msg...)
r := hint(toHint)
- R := Scalarmult1(bB1, r)
- S := biMod(biAdd(r, biMul(hint([]byte(string(Encodepoint(R))+string(blindedKey)+string(msg))), a)), l)
-
- return append(Encodepoint(R), encodeint(S)...)
+ 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 edwardsDouble(P []*big.Int) []*big.Int {
- // This is formula sequence 'dbl-2008-hwcd' from
- // http://www.hyperelliptic.org/EFD/g1p/auto-twisted-extended-1.html
- x1 := P[0]
- y1 := P[1]
- z1 := P[2]
- a := biMod(biMul(x1, x1), q)
- b := biMod(biMul(y1, y1), q)
- c := biMod(biMul(biMul(bi(2), z1), z1), q)
- e := biMod(biSub(biSub(biMul(biAdd(x1, y1), biAdd(x1, y1)), a), b), q)
- g := biAdd(biMul(a, bi(-1)), b)
- f := biSub(g, c)
- h := biSub(biMul(a, bi(-1)), b)
- x3 := biMul(e, f)
- y3 := biMul(g, h)
- t3 := biMul(e, h)
- z3 := biMul(f, g)
- return []*big.Int{biMod(x3, q), biMod(y3, q), biMod(z3, q), biMod(t3, q)}
+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 Scalarmult1(P []*big.Int, e *big.Int) []*big.Int {
+func scalarmult(P []*big.Int, e *big.Int) []*big.Int {
if e.Cmp(bi(0)) == 0 {
- return []*big.Int{bi(0), bi(1), bi(1), bi(0)}
+ return []*big.Int{bi(0), bi(1)}
}
- Q := Scalarmult1(P, biDiv(e, bi(2)))
- Q = edwardsDouble(Q)
+ Q := scalarmult(P, biDiv(e, bi(2)))
+ Q = edwards(Q, Q)
if biAnd(e, bi(1)).Int64() == 1 {
- //if e.And(e, bi(1)).Int64() == 1 {
- Q = edwardsAdd(Q, P)
+ Q = edwards(Q, P)
}
return Q
}
-func edwardsAdd(P, Q []*big.Int) []*big.Int {
- // This is formula sequence 'addition-add-2008-hwcd-3' from
- // http://www.hyperelliptic.org/EFD/g1p/auto-twisted-extended-1.html
- x1 := P[0]
- y1 := P[1]
- z1 := P[2]
- t1 := P[3]
- x2 := Q[0]
- y2 := Q[1]
- z2 := Q[2]
- t2 := Q[3]
- a := biMod(biMul(biSub(y1, x1), biSub(y2, x2)), q)
- b := biMod(biMul(biAdd(y1, x1), biAdd(y2, x2)), q)
- c := biMod(biMul(biMul(biMul(t1, bi(2)), d1), t2), q)
- dd := biMod(biMul(biMul(z1, bi(2)), z2), q)
- e := biSub(b, a)
- f := biSub(dd, c)
- g := biAdd(dd, c)
- h := biAdd(b, a)
- x3 := biMul(e, f)
- y3 := biMul(g, h)
- t3 := biMul(e, h)
- z3 := biMul(f, g)
- return []*big.Int{biMod(x3, q), biMod(y3, q), biMod(z3, q), biMod(t3, q)}
-}
-
-func Encodepoint(P []*big.Int) []byte {
- x := P[0]
- y := P[1]
- z := P[2]
- //t := P[3]
- zi := inv(z)
- x = biMod(biMul(x, zi), q)
- y = biMod(biMul(y, zi), 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()))
@@ -178,20 +139,6 @@ func hint(m []byte) *big.Int {
return sum
}
-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"
-}
-
func encodeint(y *big.Int) []byte {
bits := make([]*big.Int, 0)
for i := 0; i < b; i++ {
@@ -208,50 +155,9 @@ func encodeint(y *big.Int) []byte {
return final
}
-func PublickeyFromESK(h []byte) ed25519.PublicKey {
- a := decodeInt(h[:32])
- A := scalarmult(bB, a)
- return encodepoint(A)
-}
-
-// LoadTorKeyFromDisk load a private identity key from little-t-tor.
-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:]
-
- // The rest should be 64 bytes (a,h):
- // 32 bytes for secret scalar 'a'
- // 32 bytes for PRF key 'h'
- if len(expandedSk) != 64 {
- panic("Tor private key has the wrong length")
- }
- return expandedSk
-}
-
-func encodepoint(P []*big.Int) []byte {
- x := P[0]
- y := 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 decodeInt(s []uint8) *big.Int {
sum := bi(0)
- for i := 0; i < 256; i++ {
+ 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))
@@ -259,28 +165,6 @@ func decodeInt(s []uint8) *big.Int {
return sum
}
-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 e.And(e, bi(1)).Int64() == 1 {
- Q = edwards(Q, P)
- }
- return Q
-}
-
-func edwards(P, Q []*big.Int) []*big.Int {
- x1 := P[0]
- y1 := P[1]
- x2 := Q[0]
- y2 := 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 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)
@@ -293,10 +177,6 @@ func xrecover(y *big.Int) *big.Int {
return x
}
-func inv(x *big.Int) *big.Int {
- return expmod(x, biSub(q, bi(2)), q)
-}
-
func expmod(b, e, m *big.Int) *big.Int {
if e.Cmp(bi(0)) == 0 {
return bi(1)
@@ -308,46 +188,21 @@ func expmod(b, e, m *big.Int) *big.Int {
return t
}
-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 biExp(a, b *big.Int) *big.Int {
- return bi(0).Exp(a, b, nil)
-}
-
-func biDiv(a, b *big.Int) *big.Int {
- return bi(0).Div(a, b)
-}
-
-func biSub(a, b *big.Int) *big.Int {
- return bi(0).Sub(a, b)
-}
-
-func biAdd(a, b *big.Int) *big.Int {
- return bi(0).Add(a, b)
-}
-
-func biAnd(a, b *big.Int) *big.Int {
- return bi(0).And(a, b)
-}
-
-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)
-}
-
-func biMul(a, b *big.Int) *big.Int {
- return bi(0).Mul(a, b)
+func biFromStr(v string) (out *big.Int) {
+ out = new(big.Int)
+ _, _ = fmt.Sscan(v, out)
+ return
}
-func biMod(a, b *big.Int) *big.Int {
- return bi(0).Mod(a, b)
-}
+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) }