September 2017 Update

This commit is contained in:
Ingy döt Net 2017-09-23 10:01:46 +02:00
parent bba7bfd280
commit ba8067c3b7
14570 changed files with 153136 additions and 63871 deletions

View file

@ -0,0 +1,16 @@
USING: byte-arrays checksums checksums.sha io.binary kernel math
math.parser sequences ;
IN: rosetta-code.bitcoin.validation
CONSTANT: ALPHABET "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
: base58>bigint ( str -- n )
[ ALPHABET index ]
[ [ 58 * ] [ + ] bi* ] map-reduce ;
: base58> ( str -- bytes ) base58>bigint 25 >be ;
: btc-checksum ( bytes -- checksum-bytes )
21 head 2 [ sha-256 checksum-bytes ] times 4 head ;
: btc-valid? ( str -- ? ) base58> [ btc-checksum ] [ 4 tail* ] bi = ;

View file

@ -0,0 +1,206 @@
' version 05-04-2017
' compile with: fbc -s console
' function adapted from the SHA-256 task
Function SHA_256(test_str As String, bitcoin As ULong = 0) As String
#Macro Ch (x, y, z)
(((x) And (y)) Xor ((Not (x)) And z))
#EndMacro
#Macro Maj (x, y, z)
(((x) And (y)) Xor ((x) And (z)) Xor ((y) And (z)))
#EndMacro
#Macro sigma0 (x)
(((x) Shr 2 Or (x) Shl 30) Xor ((x) Shr 13 Or (x) Shl 19) Xor ((x) Shr 22 Or (x) Shl 10))
#EndMacro
#Macro sigma1 (x)
(((x) Shr 6 Or (x) Shl 26) Xor ((x) Shr 11 Or (x) Shl 21) Xor ((x) Shr 25 Or (x) Shl 7))
#EndMacro
#Macro sigma2 (x)
(((x) Shr 7 Or (x) Shl 25) Xor ((x) Shr 18 Or (x) Shl 14) Xor ((x) Shr 3))
#EndMacro
#Macro sigma3 (x)
(((x) Shr 17 Or (x) Shl 15) Xor ((x) Shr 19 Or (x) Shl 13) Xor ((x) Shr 10))
#EndMacro
Dim As String message = test_str ' strings are passed as ByRef's
Dim As Long i, j
Dim As UByte Ptr ww1
Dim As UInteger<32> Ptr ww4
Do
Dim As ULongInt l = Len(message)
' set the first bit after the message to 1
message = message + Chr(1 Shl 7)
' add one char to the length
Dim As ULong padding = 64 - ((l +1) Mod (512 \ 8)) ' 512 \ 8 = 64 char.
' check if we have enough room for inserting the length
If padding < 8 Then padding = padding + 64
message = message + String(padding, Chr(0)) ' adjust length
Dim As ULong l1 = Len(message) ' new length
l = l * 8 ' orignal length in bits
' create ubyte ptr to point to l ( = length in bits)
Dim As UByte Ptr ub_ptr = Cast(UByte Ptr, @l)
For i = 0 To 7 'copy length of message to the last 8 bytes
message[l1 -1 - i] = ub_ptr[i]
Next
'table of constants
Dim As UInteger<32> K(0 To ...) = _
{ &H428a2f98, &H71374491, &Hb5c0fbcf, &He9b5dba5, &H3956c25b, &H59f111f1, _
&H923f82a4, &Hab1c5ed5, &Hd807aa98, &H12835b01, &H243185be, &H550c7dc3, _
&H72be5d74, &H80deb1fe, &H9bdc06a7, &Hc19bf174, &He49b69c1, &Hefbe4786, _
&H0fc19dc6, &H240ca1cc, &H2de92c6f, &H4a7484aa, &H5cb0a9dc, &H76f988da, _
&H983e5152, &Ha831c66d, &Hb00327c8, &Hbf597fc7, &Hc6e00bf3, &Hd5a79147, _
&H06ca6351, &H14292967, &H27b70a85, &H2e1b2138, &H4d2c6dfc, &H53380d13, _
&H650a7354, &H766a0abb, &H81c2c92e, &H92722c85, &Ha2bfe8a1, &Ha81a664b, _
&Hc24b8b70, &Hc76c51a3, &Hd192e819, &Hd6990624, &Hf40e3585, &H106aa070, _
&H19a4c116, &H1e376c08, &H2748774c, &H34b0bcb5, &H391c0cb3, &H4ed8aa4a, _
&H5b9cca4f, &H682e6ff3, &H748f82ee, &H78a5636f, &H84c87814, &H8cc70208, _
&H90befffa, &Ha4506ceb, &Hbef9a3f7, &Hc67178f2 }
Dim As UInteger<32> h0 = &H6a09e667
Dim As UInteger<32> h1 = &Hbb67ae85
Dim As UInteger<32> h2 = &H3c6ef372
Dim As UInteger<32> h3 = &Ha54ff53a
Dim As UInteger<32> h4 = &H510e527f
Dim As UInteger<32> h5 = &H9b05688c
Dim As UInteger<32> h6 = &H1f83d9ab
Dim As UInteger<32> h7 = &H5be0cd19
Dim As UInteger<32> a, b, c, d, e, f, g, h
Dim As UInteger<32> t1, t2, w(0 To 63)
For j = 0 To (l1 -1) \ 64 ' split into block of 64 bytes
ww1 = Cast(UByte Ptr, @message[j * 64])
ww4 = Cast(UInteger<32> Ptr, @message[j * 64])
For i = 0 To 60 Step 4 'little endian -> big endian
Swap ww1[i ], ww1[i +3]
Swap ww1[i +1], ww1[i +2]
Next
For i = 0 To 15 ' copy the 16 32bit block into the array
W(i) = ww4[i]
Next
For i = 16 To 63 ' fill the rest of the array
w(i) = sigma3(W(i -2)) + W(i -7) + sigma2(W(i -15)) + W(i -16)
Next
a = h0 : b = h1 : c = h2 : d = h3 : e = h4 : f = h5 : g = h6 : h = h7
For i = 0 To 63
t1 = h + sigma1(e) + Ch(e, f, g) + K(i) + W(i)
t2 = sigma0(a) + Maj(a, b, c)
h = g : g = f : f = e
e = d + t1
d = c : c = b : b = a
a = t1 + t2
Next
h0 += a : h1 += b : h2 += c : h3 += d
h4 += e : h5 += f : h6 += g : h7 += h
Next j
Dim As String answer = Hex(h0, 8) + Hex(h1, 8) + Hex(h2, 8) + Hex(h3, 8) _
+ Hex(h4, 8) + Hex(h5, 8) + Hex(h6, 8) + Hex(h7, 8)
If bitcoin = 0 Then
Return LCase(answer)
Else 'conver hex value's to integer value's
message = String(32,0)
For i = 0 To 31
message[i] = Val("&h" + Mid(answer, i * 2 + 1, 2))
Next
bitcoin = 0
End If
Loop
End Function
Function conv_base58(bitcoin_address As String) As String
Dim As String base58 = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
Dim As String tmp = String(24, 0)
Dim As Long x, y, z
For x = 1 To Len(bitcoin_address) -1
z = InStr(base58, Chr(bitcoin_address[x])) -1
If z = -1 Then
Print " bitcoin address contains illegal character"
Return ""
End If
For y = 23 To 0 Step -1
z = z + tmp[y] * 58
tmp[y] = z And 255 ' test_str[y] = z Mod 256
z Shr= 8 ' z \= 256
Next
If z <> 0 Then
Print " bitcoin address is to long"
Return ""
End If
Next
z = InStr(base58, Chr(bitcoin_address[0])) -1
Return Chr(z) + tmp
End Function
' ------=< MAIN >=------
Data "1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i" ' original
Data "1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62j" ' checksum changed
Data "1NAGa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i" ' address changed
Data "0AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i" ' only 1 or 3 as first char. allowed
Data "1AGNa15ZQXAZUgFlqJ2i7Z2DPU2J6hW62i" ' illegal character in address
Dim As String tmp, result, checksum, bitcoin_address
Dim As Long i, j
For i = 1 To 5
Read bitcoin_address
Print "Bitcoin address: "; bitcoin_address;
tmp = Left(bitcoin_address,1)
If tmp <> "1" And tmp <> "3" Then
Print " first character is not 1 or 3"
Continue For
End If
' convert bitcoinaddress
tmp = conv_base58(bitcoin_address)
If tmp = "" Then Continue For
' get the checksum, last 4 digits
For j As Long = 21 To 24
checksum = checksum + LCase(Hex(tmp[j], 2))
Next
' send the first 21 characters to the SHA 256 routine
result = SHA_256(Left(tmp, 21), 2)
result = Left(result, 8) ' get the checksum (the first 8 digits (hex))
If checksum = result Then ' test the found checksum against
Print " is valid" ' the one from the address
Else
Print " is not valid, checksum fails"
End If
Next
' empty keyboard buffer
While InKey <> "" : Wend
Print : Print "hit any key to end program"
Sleep
End

View file

@ -22,7 +22,7 @@ validityCheck encodedAddress =
Just ev ->
let address = toBytes ev
addressLength = length address
in if addressLength > 24
in if addressLength > 25
then Left "Address length exceeds 25 bytes"
else
if addressLength < 4

View file

@ -1,63 +1,71 @@
private final static String ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
public static void main(String[] args) {
Assert("Test 01", ValidateBitcoinAddress("1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i"), true);
Assert("Test 02", ValidateBitcoinAddress("1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62j"), false);
Assert("Test 03", ValidateBitcoinAddress("1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nK9"), true);
Assert("Test 04", ValidateBitcoinAddress("1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62X"), false);
Assert("Test 05", ValidateBitcoinAddress("1ANNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i"), false);
Assert("Test 06", ValidateBitcoinAddress("1A Na15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i"), false);
Assert("Test 07", ValidateBitcoinAddress("BZbvjr"), false);
Assert("Test 08", ValidateBitcoinAddress("i55j"), false);
Assert("Test 09", ValidateBitcoinAddress("1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62!"), false);
Assert("Test 10", ValidateBitcoinAddress("1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62iz"), false);
Assert("Test 11", ValidateBitcoinAddress("1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62izz"), false);
Assert("Test 12", ValidateBitcoinAddress("1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nJ9"), false);
Assert("Test 13", ValidateBitcoinAddress("1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62I"), false);
}
public class BitcoinAddressValidator {
public static boolean ValidateBitcoinAddress(String addr) {
if (addr.length() < 26 || addr.length() > 35) return false;
byte[] decoded = DecodeBase58(addr, 58, 25);
if (decoded == null) return false;
private static final String ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
byte[] hash = Sha256(decoded, 0, 21, 2);
public static boolean validateBitcoinAddress(String addr) {
if (addr.length() < 26 || addr.length() > 35)
return false;
byte[] decoded = decodeBase58(addr, 25);
if (decoded == null)
return false;
return Arrays.equals(Arrays.copyOfRange(hash, 0, 4), Arrays.copyOfRange(decoded, 21, 25));
}
byte[] hash1 = sha256(Arrays.copyOfRange(decoded, 0, 21));
byte[] hash2 = sha256(hash1);
private static byte[] DecodeBase58(String input, int base, int len) {
byte[] output = new byte[len];
for (int i = 0; i < input.length(); i++) {
char t = input.charAt(i);
return Arrays.equals(Arrays.copyOfRange(hash2, 0, 4), Arrays.copyOfRange(decoded, 21, 25));
}
int p = ALPHABET.indexOf(t);
if (p == -1) return null;
for (int j = len - 1; j > 0; j--, p /= 256) {
p += base * (output[j] & 0xFF);
output[j] = (byte) (p % 256);
private static byte[] decodeBase58(String input, int len) {
byte[] output = new byte[len];
for (char t : input.toCharArray()) {
int p = ALPHABET.indexOf(t);
if (p == -1)
return null;
for (int j = len - 1; j >= 0; j--) {
p += 58 * (output[j] & 0xFF);
output[j] = (byte) (p % 256);
p /= 256;
}
if (p != 0)
return null;
}
if (p != 0) return null;
return output;
}
return output;
}
private static byte[] sha256(byte[] data) {
try {
MessageDigest md = MessageDigest.getInstance("SHA-256");
md.update(data);
return md.digest();
} catch (NoSuchAlgorithmException e) {
throw new IllegalStateException(e);
}
}
private static byte[] Sha256(byte[] data, int start, int len, int recursion) {
if (recursion == 0) return data;
public static void main(String[] args) {
assertBitcoin("1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i", true);
assertBitcoin("1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62j", false);
assertBitcoin("1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nK9", true);
assertBitcoin("1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62X", false);
assertBitcoin("1ANNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i", false);
assertBitcoin("1A Na15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i", false);
assertBitcoin("BZbvjr", false);
assertBitcoin("i55j", false);
assertBitcoin("1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62!", false);
assertBitcoin("1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62iz", false);
assertBitcoin("1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62izz", false);
assertBitcoin("1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nJ9", false);
assertBitcoin("1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62I", false);
}
try {
MessageDigest md = MessageDigest.getInstance("SHA-256");
md.update(Arrays.copyOfRange(data, start, start + len));
return Sha256(md.digest(), 0, 32, recursion - 1);
} catch (NoSuchAlgorithmException e) {
return null;
private static void assertBitcoin(String address, boolean expected) {
boolean actual = validateBitcoinAddress(address);
if (actual != expected)
throw new AssertionError(String.format("Expected %s for %s, but got %s.", expected, address, actual));
}
}
public static void Assert(String name, boolean value, boolean expected) {
if (value ^ expected)
throw new Error("Test " + name + " failed");
else
System.out.println(name + " passed");
}

View file

@ -0,0 +1,60 @@
import java.security.MessageDigest
object Bitcoin {
private const val ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
private fun ByteArray.contentEquals(other: ByteArray): Boolean {
if (this.size != other.size) return false
return (0 until this.size).none { this[it] != other[it] }
}
private fun decodeBase58(input: String): ByteArray? {
val output = ByteArray(25)
for (c in input) {
var p = ALPHABET.indexOf(c)
if (p == -1) return null
for (j in 24 downTo 1) {
p += 58 * (output[j].toInt() and 0xff)
output[j] = (p % 256).toByte()
p = p shr 8
}
if (p != 0) return null
}
return output
}
private fun sha256(data: ByteArray, start: Int, len: Int, recursion: Int): ByteArray {
if (recursion == 0) return data
val md = MessageDigest.getInstance("SHA-256")
md.update(data.sliceArray(start until start + len))
return sha256(md.digest(), 0, 32, recursion - 1)
}
fun validateAddress(address: String): Boolean {
if (address.length !in 26..35) return false
val decoded = decodeBase58(address)
if (decoded == null) return false
val hash = sha256(decoded, 0, 21, 2)
return hash.sliceArray(0..3).contentEquals(decoded.sliceArray(21..24))
}
}
fun main(args: Array<String>) {
val addresses = arrayOf(
"1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i",
"1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62j",
"1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nK9",
"1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62X",
"1ANNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i",
"1A Na15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i",
"BZbvjr",
"i55j",
"1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62!",
"1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62iz",
"1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62izz",
"1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nJ9",
"1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62I"
)
for (address in addresses)
println("${address.padEnd(36)} -> ${if (Bitcoin.validateAddress(address)) "valid" else "invalid"}")
}

View file

@ -0,0 +1,54 @@
extern crate crypto;
use crypto::digest::Digest;
use crypto::sha2::Sha256;
const DIGITS58: [char; 58] = ['1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'];
fn main() {
println!("{}", validate_address("1AGNa15ZQXAZUgFiqJ3i7Z2DPU2J6hW62i"));
println!("{}", validate_address("1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i"));
println!("{}", validate_address("17NdbrSGoUotzeGCcMMCqnFkEvLymoou9j"));
println!("{}", validate_address("17NdbrSGoUotzeGCcMMC?nFkEvLymoou9j"));
}
fn validate_address(address: &str) -> bool {
let decoded = match from_base58(address, 25) {
Ok(x) => x,
Err(_) => return false
};
if decoded[0] != 0 {
return false;
}
let mut sha = Sha256::new();
sha.input(&decoded[0..21]);
let mut first_round = vec![0u8; sha.output_bytes()];
sha.result(&mut first_round);
sha.reset();
sha.input(&first_round);
let mut second_round = vec![0u8; sha.output_bytes()];
sha.result(&mut second_round);
if second_round[0..4] != decoded[21..25] {
return false
}
true
}
fn from_base58(encoded: &str, size: usize) -> Result<Vec<u8>, String> {
let mut res: Vec<u8> = vec![0; size];
for base58_value in encoded.chars() {
let mut value: u32 = match DIGITS58
.iter()
.position(|x| *x == base58_value){
Some(x) => x as u32,
None => return Err(String::from("Invalid character found in encoded string."))
};
for result_index in (0..size).rev() {
value += 58 * res[result_index] as u32;
res[result_index] = (value % 256) as u8;
value /= 256;
}
}
Ok(res)
}

View file

@ -0,0 +1,25 @@
var [const] MsgHash=Import("zklMsgHash"); // SHA-256, etc
const symbols="123456789" // 58 characters: no cap i,o; ell, zero
"ABCDEFGHJKLMNPQRSTUVWXYZ"
"abcdefghijkmnopqrstuvwxyz";
fcn unbase58(str){ // --> Data (byte bucket)
out:=Data().fill(0,25);
str.pump(Void,symbols.index,'wrap(n){ // throws on out of range
[24..0,-1].reduce('wrap(c,idx){
c+=58*out[idx]; // throws if not enough data
out[idx]=c;
c/256; // should be zero when done
},n) : if(_) throw(Exception.ValueError("address too long"));
});
out;
}
fcn coinValide(addr){
reg dec,chkSum;
try{ dec=unbase58(addr) }catch{ return(False) }
chkSum=dec[-4,*]; dec.del(21,*);
// hash then hash the hash --> binary hash (instead of hex string)
(2).reduce(MsgHash.SHA256.fp1(1,dec),dec); // dec is i/o buffer
dec[0,4]==chkSum;
}

View file

@ -0,0 +1,6 @@
T("1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i","1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nK9",
"1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62X", // checksum changed, original data.
"1ANNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i", // data changed, original checksum.
"1A Na15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i", // invalid chars
"1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62izz", // too long
).apply(coinValide).println();