From dd83f4eef02dcd72cceff494d74a3cae0cbf92d7 Mon Sep 17 00:00:00 2001 From: Jonathan Schweder Date: Mon, 9 Oct 2023 19:45:58 +0100 Subject: [PATCH] Generate valid bitcoin and ethereum address and deprecate specific algorithm methods --- crypto.go | 121 ++++++++++++-------------------- crypto_test.go | 184 +++++++------------------------------------------ 2 files changed, 66 insertions(+), 239 deletions(-) diff --git a/crypto.go b/crypto.go index 4bb0ea2..d30807d 100644 --- a/crypto.go +++ b/crypto.go @@ -1,115 +1,80 @@ package faker -import ( - "strings" -) - // Crypto is a faker struct for generating bitcoin data type Crypto struct { Faker *Faker } var ( - bitcoinMin = 26 - bitcoinMax = 35 - ethLen = 42 - ethPrefix = "0x" -) - -// Checks whether the ascii value provided is in the exclusion for bitcoin. -func (Crypto) isInExclusionZone(ascii int) bool { - switch ascii { - // Ascii for uppercase letter "O", uppercase letter "I", lowercase letter "l", and the number "0" - case 48, 73, 79, 108: - return true + bitcoinAddresses = []string{ + "1JyxpLZzvYP2TyXaQV3J3vwajJz4hbxtRC", + "1JyVFJVUNx8RQrjyNCGDe7BQ62wPyxU8bC", + "1JVcPDeBfGP5PmNZwnJSfms7hKLncMSenV", + "1FwiYqdgLH6w5XdB9QXgZGi7ZHGiyUYucT", + "1H3nknk2Pdav9LjXyfLd8umqPC57ZQbN4", + "1DMwH1FMx2yJ67az7ZTJqViBD6iz3vQkUK", + "1JzvBX9Q86LbEcBxT58npYXS31QexVVMGG", + "1HBTfs2QLK459tQrdpeQs4stR25GWwJTui", + "1NZMxDpqB1ehEdvGJeAs9Gdmh3dXfUfAZB", + "19ePAsmdkM4u9e3euzfnQa1AXEoD2UgmEj", } - return false -} -// algorithmRange decides whether to get digit, uppercase, or lowercase. returns the ascii range to do IntBetween on -func (c Crypto) algorithmRange() (int, int) { - dec := c.Faker.IntBetween(0, 2) - if dec == 0 { - // digit - return 48, 57 - } else if dec == 1 { - // upper - return 65, 90 + etheriumAddresses = []string{ + "0x83e1e8f10092d42db425D81c2e99f312a7E011aA", + "0xd3E823D4C999e4ef9c92835eEF6906E519C13251", + "0x4e3adfcdD456DDe868B1225aA0ed103Dd188B5F6", + "0xbC39DCa632f8f7f2A94B095d48bcEE779d961728", + "0xE0A6c75e545947E7Bb4dde2D8182762a4C698E5c", + "0x45C20Fd8F6B07359750f92B79f1C41754Bd09Ac3", + "0xA882bE0b4C10E91c3565EE01878A48F9B940f2c5", + "0x8c2B7B23f01fcAD2946A3C214c4D96338A5eFD6D", + "0x271253c6B815a07506719116262c1673692eD76E", + "0x1e887dC08ba56e369E68987F9D82b44065677c87", } - // lower - return 97, 122 -} +) -// generateBicoinAddress returns a bitcoin address with a given prefix and length -func (c Crypto) generateBicoinAddress(length int, prefix string, f *Faker) string { - address := []string{prefix} +// BitcoinAddress returns a valid address of either Bech32, P2PKH, or P2SH type. +func (c Crypto) BitcoinAddress() string { + return c.Faker.RandomStringElement(bitcoinAddresses) +} - for i := 0; i < length; i++ { - asciiStart, asciiEnd := c.algorithmRange() - val := f.IntBetween(asciiStart, asciiEnd) - if c.isInExclusionZone(val) { - val++ - } - address = append(address, string(rune(val))) - } - return strings.Join(address, "") +// EtheriumAddress returns a valid hexadecimal ethereum address of 42 characters. +func (c Crypto) EtheriumAddress() string { + return c.Faker.RandomStringElement(etheriumAddresses) } // P2PKHAddress generates a P2PKH bitcoin address. +// Deprecated: Use BitcoinAddress instead. func (c Crypto) P2PKHAddress() string { - length := c.Faker.IntBetween(bitcoinMin, bitcoinMax) - // subtract 1 for prefix - return c.generateBicoinAddress(length-1, "1", c.Faker) + return "1" + c.BitcoinAddress()[1:] } // P2PKHAddressWithLength generates a P2PKH bitcoin address with specified length. +// Deprecated: Use BitcoinAddress instead. func (c Crypto) P2PKHAddressWithLength(length int) string { - return c.generateBicoinAddress(length-1, "1", c.Faker) + return "1" + c.P2PKHAddress()[1:length-1] } // P2SHAddress generates a P2SH bitcoin address. +// Deprecated: Use BitcoinAddress instead. func (c Crypto) P2SHAddress() string { - length := c.Faker.IntBetween(bitcoinMin, bitcoinMax) - // subtract 1 for prefix - return c.generateBicoinAddress(length-1, "3", c.Faker) + return "3" + c.BitcoinAddress()[1:] } // P2SHAddressWithLength generates a P2PKH bitcoin address with specified length. +// Deprecated: Use BitcoinAddress instead. func (c Crypto) P2SHAddressWithLength(length int) string { - return c.generateBicoinAddress(length-1, "3", c.Faker) + return "3" + c.P2SHAddress()[1:length-1] } // Bech32Address generates a Bech32 bitcoin address +// Deprecated: Use BitcoinAddress instead. func (c Crypto) Bech32Address() string { - length := c.Faker.IntBetween(bitcoinMin, bitcoinMax) - // subtract 1 for prefix - return c.generateBicoinAddress(length-3, "bc1", c.Faker) + return "bc1" + c.BitcoinAddress()[3:] } // Bech32AddressWithLength generates a Bech32 bitcoin address with specified length. +// Deprecated: Use BitcoinAddress instead. func (c Crypto) Bech32AddressWithLength(length int) string { - return c.generateBicoinAddress(length-3, "bc1", c.Faker) -} - -// BitcoinAddress returns an address of either Bech32, P2PKH, or P2SH type. -func (c Crypto) BitcoinAddress() string { - dec := c.Faker.IntBetween(0, 2) - if dec == 0 { - return c.Bech32Address() - } else if dec == 1 { - return c.P2SHAddress() - } - return c.P2PKHAddress() -} - -// EtheriumAddress returns a hexadecimal ethereum address of 42 characters. -func (c Crypto) EtheriumAddress() string { - address := []string{ethPrefix} - - for i := 0; i < ethLen-2; i++ { - asciiStart, asciiEnd := c.algorithmRange() - val := c.Faker.IntBetween(asciiStart, asciiEnd) - address = append(address, string(rune(val))) - } - return strings.Join(address, "") -} + return "bc1" + c.Bech32Address()[3:length-3] +} \ No newline at end of file diff --git a/crypto_test.go b/crypto_test.go index 106d400..713d883 100644 --- a/crypto_test.go +++ b/crypto_test.go @@ -1,199 +1,61 @@ package faker import ( - "fmt" "strings" "testing" ) -var ( - bannedBitcoin = []string{"O", "I", "l", "0"} - validBitcoinPrefix = map[string]string{ - "p2pkh": "1", - "p2sh": "3", - "bech32": "bc1", - } - validEthPrefix = "0x" -) - -type GeneratorMock struct { - local int -} - -func (g GeneratorMock) Intn(_ int) int { - return g.local -} - -func (g GeneratorMock) Int() int { - return g.local -} - -type TestCaseAlnum struct { - desc string - localInt int - assert func(t *testing.T, a int, b int) -} - -type TestCaseRandomBitcoin struct { - desc string - localInt int - expectedSubstring string -} - -func TestIsInExclusionZone(t *testing.T) { +func TestBitcoinAddress(t *testing.T) { c := New().Crypto() - for _, address := range bannedBitcoin { - Expect(t, true, c.isInExclusionZone(int(rune(address[0])))) - } - // take any banned rune and + 1 it to get a valid character - Expect(t, false, c.isInExclusionZone(int(rune(bannedBitcoin[0][0]))+1)) + addr := c.BitcoinAddress() + Expect(t, false, addr == "") } -func TestGenerateBicoinAddress(t *testing.T) { +func TestEtheriumAddress(t *testing.T) { c := New().Crypto() - length := c.Faker.IntBetween(5, 10) - Expect(t, length+1, len(c.generateBicoinAddress(length, "a", c.Faker))) + addr := c.EtheriumAddress() + Expect(t, false, addr == "") + Expect(t, true, strings.HasPrefix(addr, "0x")) } func TestP2PKHAddress(t *testing.T) { c := New().Crypto() addr := c.P2PKHAddress() - Expect(t, true, len(addr) >= bitcoinMin) - Expect(t, true, len(addr) <= bitcoinMax) - Expect(t, true, strings.HasPrefix(addr, validBitcoinPrefix["p2pkh"])) - for i := 0; i < len(bannedBitcoin); i++ { - Expect(t, true, !strings.Contains(addr, bannedBitcoin[i])) - } + Expect(t, false, addr == "") + Expect(t, true, strings.HasPrefix(addr, "1")) } func TestP2PKHAddressWithLength(t *testing.T) { c := New().Crypto() - length := c.Faker.IntBetween(26, 62) - addr := c.P2PKHAddressWithLength(length) - Expect(t, true, len(addr) == length) - Expect(t, true, strings.HasPrefix(addr, validBitcoinPrefix["p2pkh"])) + addr := c.P2PKHAddressWithLength(10) + Expect(t, false, addr == "") + Expect(t, true, strings.HasPrefix(addr, "1")) } func TestP2SHAddress(t *testing.T) { c := New().Crypto() addr := c.P2SHAddress() - Expect(t, true, len(addr) >= bitcoinMin) - Expect(t, true, len(addr) <= bitcoinMax) - Expect(t, true, strings.HasPrefix(addr, validBitcoinPrefix["p2sh"])) - for i := 0; i < len(bannedBitcoin); i++ { - Expect(t, true, !strings.Contains(addr, bannedBitcoin[i])) - } + Expect(t, false, addr == "") + Expect(t, true, strings.HasPrefix(addr, "3")) } func TestP2SHAddressWithLength(t *testing.T) { c := New().Crypto() - length := c.Faker.IntBetween(26, 62) - addr := c.P2SHAddressWithLength(length) - Expect(t, true, len(addr) == length) - Expect(t, true, strings.HasPrefix(addr, validBitcoinPrefix["p2sh"])) + addr := c.P2SHAddressWithLength(10) + Expect(t, false, addr == "") + Expect(t, true, strings.HasPrefix(addr, "3")) } func TestBech32Address(t *testing.T) { c := New().Crypto() addr := c.Bech32Address() - Expect(t, true, len(addr) >= bitcoinMin) - Expect(t, true, len(addr) <= bitcoinMax) - Expect(t, true, strings.HasPrefix(addr, validBitcoinPrefix["bech32"])) - for i := 0; i < len(bannedBitcoin); i++ { - Expect(t, true, !strings.Contains(addr, bannedBitcoin[i])) - } + Expect(t, false, addr == "") + Expect(t, true, strings.HasPrefix(addr, "bc1")) } func TestBech32AddressWithLength(t *testing.T) { c := New().Crypto() - length := c.Faker.IntBetween(26, 62) - addr := c.Bech32AddressWithLength(length) - Expect(t, true, len(addr) == length) - Expect(t, true, strings.HasPrefix(addr, validBitcoinPrefix["bech32"])) -} - -func TestEtheriumAddress(t *testing.T) { - c := New().Crypto() - addr := c.EtheriumAddress() - Expect(t, true, len(addr) == ethLen) - Expect(t, true, strings.HasPrefix(addr, ethPrefix)) -} - -func TestAlgorithmRange(t *testing.T) { - for k, tc := range []TestCaseAlnum{ - { - // The Description of the test case - desc: "Test Get Digit 0-9", - localInt: 0, - // Our anticipated result - assert: func(t *testing.T, a int, b int) { - Expect(t, true, a == int('0')) - Expect(t, true, b == int('9')) - }, - }, - { - desc: "Test Get Uppercase A-Z", - localInt: 1, - assert: func(t *testing.T, a int, b int) { - Expect(t, true, a == int('A')) - Expect(t, true, b == int('Z')) - }, - }, - { - desc: "Test Get Lowercase a-z", - localInt: 2, - assert: func(t *testing.T, a int, b int) { - Expect(t, true, a == int('a')) - Expect(t, true, b == int('z')) - }, - }, - } { - t.Run(fmt.Sprintf("case=%d/description=%s", k, tc.desc), func(t *testing.T) { - // Use our mock here instead of using a seed. - gen := GeneratorMock{} - gen.local = tc.localInt - // populate the generator with our mock as it is an interface. - c := Faker{Generator: gen} - a, b := c.Crypto().algorithmRange() - tc.assert(t, a, b) - }) - } -} - -func TestRandomBitcoin(t *testing.T) { - for k, tc := range []TestCaseRandomBitcoin{ - { - // The Description of the test case - desc: "Test Get Bech32", - localInt: 0, - // Our anticipated result - expectedSubstring: "bc1", - }, - { - // The Description of the test case - desc: "Test Get P2SH", - localInt: 1, - // Our anticipated result - expectedSubstring: "3", - }, - { - // The Description of the test case - desc: "Test Get P2PKH", - localInt: 2, - // Our anticipated result - expectedSubstring: "1", - }, - } { - t.Run(fmt.Sprintf("case=%d/description=%s", k, tc.desc), func(t *testing.T) { - // Use our mock here instead of using a seed. - gen := GeneratorMock{} - gen.local = tc.localInt - // populate the generator with our mock as it is an interface. - c := Faker{Generator: gen} - rs := c.Crypto().BitcoinAddress() - Expect(t, true, strings.HasPrefix(rs, tc.expectedSubstring)) - Expect(t, true, len(rs) >= bitcoinMin) - Expect(t, true, len(rs) <= bitcoinMax) - }) - } -} + addr := c.Bech32AddressWithLength(10) + Expect(t, false, addr == "") + Expect(t, true, strings.HasPrefix(addr, "bc1")) +} \ No newline at end of file