-
-
Notifications
You must be signed in to change notification settings - Fork 60
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Revert changes done to crypto to make it less random (#154)
* Revert "Issue 70 (#153)" This reverts commit a20ac58. * Deprecate Bech32AddressWithLength, Bech32Address, P2SHAddress, P2PKHAddressWithLength, P2PKHAddress --------- Co-authored-by: Jonathan Schweder <jonathanschweder@amazon.com>
- Loading branch information
Showing
2 changed files
with
243 additions
and
64 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,80 +1,121 @@ | ||
package faker | ||
|
||
import ( | ||
"strings" | ||
) | ||
|
||
// Crypto is a faker struct for generating bitcoin data | ||
type Crypto struct { | ||
Faker *Faker | ||
} | ||
|
||
var ( | ||
bitcoinAddresses = []string{ | ||
"1JyxpLZzvYP2TyXaQV3J3vwajJz4hbxtRC", | ||
"1JyVFJVUNx8RQrjyNCGDe7BQ62wPyxU8bC", | ||
"1JVcPDeBfGP5PmNZwnJSfms7hKLncMSenV", | ||
"1FwiYqdgLH6w5XdB9QXgZGi7ZHGiyUYucT", | ||
"1H3nknk2Pdav9LjXyfLd8umqPC57ZQbN4", | ||
"1DMwH1FMx2yJ67az7ZTJqViBD6iz3vQkUK", | ||
"1JzvBX9Q86LbEcBxT58npYXS31QexVVMGG", | ||
"1HBTfs2QLK459tQrdpeQs4stR25GWwJTui", | ||
"1NZMxDpqB1ehEdvGJeAs9Gdmh3dXfUfAZB", | ||
"19ePAsmdkM4u9e3euzfnQa1AXEoD2UgmEj", | ||
} | ||
bitcoinMin = 26 | ||
bitcoinMax = 35 | ||
ethLen = 42 | ||
ethPrefix = "0x" | ||
) | ||
|
||
etheriumAddresses = []string{ | ||
"0x83e1e8f10092d42db425D81c2e99f312a7E011aA", | ||
"0xd3E823D4C999e4ef9c92835eEF6906E519C13251", | ||
"0x4e3adfcdD456DDe868B1225aA0ed103Dd188B5F6", | ||
"0xbC39DCa632f8f7f2A94B095d48bcEE779d961728", | ||
"0xE0A6c75e545947E7Bb4dde2D8182762a4C698E5c", | ||
"0x45C20Fd8F6B07359750f92B79f1C41754Bd09Ac3", | ||
"0xA882bE0b4C10E91c3565EE01878A48F9B940f2c5", | ||
"0x8c2B7B23f01fcAD2946A3C214c4D96338A5eFD6D", | ||
"0x271253c6B815a07506719116262c1673692eD76E", | ||
"0x1e887dC08ba56e369E68987F9D82b44065677c87", | ||
// 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 | ||
} | ||
) | ||
return false | ||
} | ||
|
||
// BitcoinAddress returns a valid address of either Bech32, P2PKH, or P2SH type. | ||
func (c Crypto) BitcoinAddress() string { | ||
return c.Faker.RandomStringElement(bitcoinAddresses) | ||
// 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 | ||
} | ||
// lower | ||
return 97, 122 | ||
} | ||
|
||
// EtheriumAddress returns a valid hexadecimal ethereum address of 42 characters. | ||
func (c Crypto) EtheriumAddress() string { | ||
return c.Faker.RandomStringElement(etheriumAddresses) | ||
// 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} | ||
|
||
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, "") | ||
} | ||
|
||
// P2PKHAddress generates a P2PKH bitcoin address. | ||
// Deprecated: Use BitcoinAddress instead. | ||
// Deprecated: Please use BitcoinAddress instead. | ||
func (c Crypto) P2PKHAddress() string { | ||
return "1" + c.BitcoinAddress()[1:] | ||
length := c.Faker.IntBetween(bitcoinMin, bitcoinMax) | ||
// subtract 1 for prefix | ||
return c.generateBicoinAddress(length-1, "1", c.Faker) | ||
} | ||
|
||
// P2PKHAddressWithLength generates a P2PKH bitcoin address with specified length. | ||
// Deprecated: Use BitcoinAddress instead. | ||
// Deprecated: Please use BitcoinAddress instead. | ||
func (c Crypto) P2PKHAddressWithLength(length int) string { | ||
return "1" + c.P2PKHAddress()[1:length-1] | ||
return c.generateBicoinAddress(length-1, "1", c.Faker) | ||
} | ||
|
||
// P2SHAddress generates a P2SH bitcoin address. | ||
// Deprecated: Use BitcoinAddress instead. | ||
// Deprecated: Please use BitcoinAddress instead. | ||
func (c Crypto) P2SHAddress() string { | ||
return "3" + c.BitcoinAddress()[1:] | ||
length := c.Faker.IntBetween(bitcoinMin, bitcoinMax) | ||
// subtract 1 for prefix | ||
return c.generateBicoinAddress(length-1, "3", c.Faker) | ||
} | ||
|
||
// P2SHAddressWithLength generates a P2PKH bitcoin address with specified length. | ||
// Deprecated: Use BitcoinAddress instead. | ||
// Deprecated: Please use BitcoinAddress instead. | ||
func (c Crypto) P2SHAddressWithLength(length int) string { | ||
return "3" + c.P2SHAddress()[1:length-1] | ||
return c.generateBicoinAddress(length-1, "3", c.Faker) | ||
} | ||
|
||
// Bech32Address generates a Bech32 bitcoin address | ||
// Deprecated: Use BitcoinAddress instead. | ||
// Deprecated: Please use BitcoinAddress instead. | ||
func (c Crypto) Bech32Address() string { | ||
return "bc1" + c.BitcoinAddress()[3:] | ||
length := c.Faker.IntBetween(bitcoinMin, bitcoinMax) | ||
// subtract 1 for prefix | ||
return c.generateBicoinAddress(length-3, "bc1", c.Faker) | ||
} | ||
|
||
// Bech32AddressWithLength generates a Bech32 bitcoin address with specified length. | ||
// Deprecated: Use BitcoinAddress instead. | ||
// Deprecated: Please use BitcoinAddress instead. | ||
func (c Crypto) Bech32AddressWithLength(length int) string { | ||
return "bc1" + c.Bech32Address()[3:length-3] | ||
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, "") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,61 +1,199 @@ | ||
package faker | ||
|
||
import ( | ||
"fmt" | ||
"strings" | ||
"testing" | ||
) | ||
|
||
func TestBitcoinAddress(t *testing.T) { | ||
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) { | ||
c := New().Crypto() | ||
addr := c.BitcoinAddress() | ||
Expect(t, false, addr == "") | ||
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)) | ||
} | ||
|
||
func TestEtheriumAddress(t *testing.T) { | ||
func TestGenerateBicoinAddress(t *testing.T) { | ||
c := New().Crypto() | ||
addr := c.EtheriumAddress() | ||
Expect(t, false, addr == "") | ||
Expect(t, true, strings.HasPrefix(addr, "0x")) | ||
length := c.Faker.IntBetween(5, 10) | ||
Expect(t, length+1, len(c.generateBicoinAddress(length, "a", c.Faker))) | ||
} | ||
|
||
func TestP2PKHAddress(t *testing.T) { | ||
c := New().Crypto() | ||
addr := c.P2PKHAddress() | ||
Expect(t, false, addr == "") | ||
Expect(t, true, strings.HasPrefix(addr, "1")) | ||
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])) | ||
} | ||
} | ||
|
||
func TestP2PKHAddressWithLength(t *testing.T) { | ||
c := New().Crypto() | ||
addr := c.P2PKHAddressWithLength(10) | ||
Expect(t, false, addr == "") | ||
Expect(t, true, strings.HasPrefix(addr, "1")) | ||
length := c.Faker.IntBetween(26, 62) | ||
addr := c.P2PKHAddressWithLength(length) | ||
Expect(t, true, len(addr) == length) | ||
Expect(t, true, strings.HasPrefix(addr, validBitcoinPrefix["p2pkh"])) | ||
} | ||
|
||
func TestP2SHAddress(t *testing.T) { | ||
c := New().Crypto() | ||
addr := c.P2SHAddress() | ||
Expect(t, false, addr == "") | ||
Expect(t, true, strings.HasPrefix(addr, "3")) | ||
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])) | ||
} | ||
} | ||
|
||
func TestP2SHAddressWithLength(t *testing.T) { | ||
c := New().Crypto() | ||
addr := c.P2SHAddressWithLength(10) | ||
Expect(t, false, addr == "") | ||
Expect(t, true, strings.HasPrefix(addr, "3")) | ||
length := c.Faker.IntBetween(26, 62) | ||
addr := c.P2SHAddressWithLength(length) | ||
Expect(t, true, len(addr) == length) | ||
Expect(t, true, strings.HasPrefix(addr, validBitcoinPrefix["p2sh"])) | ||
} | ||
|
||
func TestBech32Address(t *testing.T) { | ||
c := New().Crypto() | ||
addr := c.Bech32Address() | ||
Expect(t, false, addr == "") | ||
Expect(t, true, strings.HasPrefix(addr, "bc1")) | ||
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])) | ||
} | ||
} | ||
|
||
func TestBech32AddressWithLength(t *testing.T) { | ||
c := New().Crypto() | ||
addr := c.Bech32AddressWithLength(10) | ||
Expect(t, false, addr == "") | ||
Expect(t, true, strings.HasPrefix(addr, "bc1")) | ||
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) | ||
}) | ||
} | ||
} |