dkforest

A forum and chat platform (onion)
git clone https://git.dasho.dev/n0tr1v/dkforest.git
Log | Files | Refs | LICENSE

commit 87142f1fb37f283ac414f106ae472570a1b81a9d
parent a879a6e6c101872e5185d9d99a8e8df932effaa6
Author: n0tr1v <n0tr1v@protonmail.com>
Date:   Sun, 29 Jan 2023 13:17:25 -0800

cleanup

Diffstat:
Mcmd/onion_signer/main.go | 311+++++++++++++++++++++----------------------------------------------------------
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) }