diff options
| author | Mohammad S Anwar <Mohammad.Anwar@yahoo.com> | 2023-04-07 01:22:50 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-04-07 01:22:50 +0100 |
| commit | b2e65f315c9226ab6603ade45d6e41fc53e7e431 (patch) | |
| tree | 4651a3c510706eb4c04194a93245a869b59bb29a | |
| parent | a9f1bafbb89d0122d109abab5dfe42e16c47a2a2 (diff) | |
| parent | 26a44e8952dd2c838d2f5d9fd8f9d799ec3fd53f (diff) | |
| download | perlweeklychallenge-club-b2e65f315c9226ab6603ade45d6e41fc53e7e431.tar.gz perlweeklychallenge-club-b2e65f315c9226ab6603ade45d6e41fc53e7e431.tar.bz2 perlweeklychallenge-club-b2e65f315c9226ab6603ade45d6e41fc53e7e431.zip | |
Merge pull request #7846 from pauloscustodio/master
Add solutions
23 files changed, 1020 insertions, 24 deletions
diff --git a/challenge-001/paulo-custodio/test.pl b/challenge-001/paulo-custodio/test.pl index 7efe038555..118c4fee8b 100644 --- a/challenge-001/paulo-custodio/test.pl +++ b/challenge-001/paulo-custodio/test.pl @@ -52,7 +52,7 @@ for my $lang (grep {-d} sort keys %LANG) { next unless $TESTS{$lang}; for $prog (path($lang)->children(qr/\.$LANG{$lang}$/)) { - $prog->basename =~ /^ch[-_](.*)\.$LANG{$lang}$/ or die $prog; + $prog->basename =~ /^ch[-_](.*)\.$LANG{$lang}$/ or next; my $task = $1; # compile if needed diff --git a/challenge-014/paulo-custodio/c/ch-1.c b/challenge-014/paulo-custodio/c/ch-1.c new file mode 100644 index 0000000000..32796436e3 --- /dev/null +++ b/challenge-014/paulo-custodio/c/ch-1.c @@ -0,0 +1,56 @@ +/* +Challenge 014 + +Challenge #1 +Write a script to generate Van Eck’s sequence starts with 0. For more +information, please check out wikipedia page. This challenge was proposed by +team member Andrezgz. +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <stdbool.h> + +void* check_mem(void* p) { + if (!p) { + fputs("Out of memory", stderr); + exit(EXIT_FAILURE); + } + return p; +} + +int* van_eck_seq(int N) { + int* nums = check_mem(malloc(N * sizeof(int))); + nums[0] = nums[1] = 0; + for (int i = 2; i < N; i++) { + bool found = false; + for (int m = i-2; !found && m >= 0; m--) { + if (nums[m] == nums[i-1]) { + nums[i] = i-1-m; + found = true; + } + } + if (!found) + nums[i] = 0; + } + return nums; +} + +int main(int argc, char* argv[]) { + if (argc != 2) { + fputs("usage: ch-1 N\n", stderr); + return EXIT_FAILURE; + } + + int N = atoi(argv[1]); + int* nums = van_eck_seq(N); + + const char* sep = ""; + for (int i = 0; i < N; i++) { + printf("%s%d", sep, nums[i]); + sep = ", "; + } + printf("\n"); + + free(nums); +} diff --git a/challenge-014/paulo-custodio/c/ch-2.c b/challenge-014/paulo-custodio/c/ch-2.c new file mode 100644 index 0000000000..ed96667a1e --- /dev/null +++ b/challenge-014/paulo-custodio/c/ch-2.c @@ -0,0 +1,195 @@ +/* +Challenge 014 + +Challenge #2 +Using only the official postal (2-letter) abbreviations for the 50 U.S. +states, write a script to find the longest English word you can spell? Here +is the list of U.S. states abbreviations as per wikipedia page. This challenge +was proposed by team member Neil Bowers. + +For example, +Pennsylvania + Connecticut = PACT +Wisconsin + North Dakota = WIND +Maine + Alabama = MEAL +California + Louisiana + Massachusetts + Rhode Island = Calamari +*/ + +#include <assert.h> +#include <ctype.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#define LU_IDX(a,b) (((a)-'A')*26 + ((b)-'A')) + +struct us_states { + const char* key; + const char* name; +}; + +struct us_states lut_us_states[] = { + {"AL", "Alabama"}, + {"AK", "Alaska"}, + {"AZ", "Arizona"}, + {"AR", "Arkansas"}, + {"CA", "California"}, + {"CO", "Colorado"}, + {"CT", "Connecticut"}, + {"DE", "Delaware"}, + {"FL", "Florida"}, + {"GA", "Georgia"}, + {"HI", "Hawaii"}, + {"ID", "Idaho"}, + {"IL", "Illinois"}, + {"IN", "Indiana"}, + {"IA", "Iowa"}, + {"KS", "Kansas"}, + {"KY", "Kentucky"}, + {"LA", "Louisiana"}, + {"ME", "Maine"}, + {"MD", "Maryland"}, + {"MA", "Massachusetts"}, + {"MI", "Michigan"}, + {"MN", "Minnesota"}, + {"MS", "Mississippi"}, + {"MO", "Missouri"}, + {"MT", "Montana"}, + { "NE", "Nebraska" }, + { "NV", "Nevada" }, + { "NH", "New Hampshire" }, + { "NJ", "New Jersey" }, + { "NM", "New Mexico" }, + { "NY", "New York" }, + { "NC", "North Carolina" }, + { "ND", "North Dakota" }, + { "OH", "Ohio" }, + { "OK", "Oklahoma" }, + { "OR", "Oregon" }, + { "PA", "Pennsylvania" }, + { "RI", "Rhode Island" }, + { "SC", "South Carolina" }, + { "SD", "South Dakota" }, + { "TN", "Tennessee" }, + { "TX", "Texas" }, + { "UT", "Utah" }, + { "VT", "Vermont" }, + { "VA", "Virginia" }, + { "WA", "Washington" }, + { "WV", "West Virginia" }, + { "WI", "Wisconsin" }, + { "WY", "Wyoming" }, + { NULL, NULL }, +}; + +const char* lut_states[LU_IDX('Z', 'Z') + 1]; + +void* check_mem(void* p) { + if (!p) { + fputs("Out of memory", stderr); + exit(EXIT_FAILURE); + } + return p; +} + +void build_lookup_table() { + for (struct us_states* p = lut_us_states; p->key != NULL; p++) { + int idx = LU_IDX(toupper(p->key[0]), toupper(p->key[1])); + assert(lut_states[idx] == NULL); + lut_states[idx] = p->name; + } +} + +const char* lookup_state(const char* str) { + if (!isalpha(str[0]) || !isalpha(str[1])) + return NULL; + else { + int idx = LU_IDX(toupper(str[0]), toupper(str[1])); + return lut_states[idx]; + } +} + +char* state_words(const char* word) { + char text[BUFSIZ]; + + if (strlen(word) % 2 != 0) // odd number of chars + return NULL; + + text[0] = '\0'; + const char* sep = ""; + for (int i = 0; i < strlen(word); i += 2) { + const char* state = lookup_state(word + i); + if (state == NULL) + return NULL; // no state found + sprintf(text + strlen(text), "%s%s", sep, state); + sep = " + "; + } + + return check_mem(strdup(text)); +} + +char* chomp(char* str) { + char* p = str + strlen(str) - 1; + while (p >= str && isspace(*p)) + *p = '\0'; + return str; +} + +char** search_words(const char* dictionary) { + FILE* fp = fopen(dictionary, "r"); + if (fp == NULL) { + perror(dictionary); + exit(EXIT_FAILURE); + } + + // array to return list + int N = 0; + char** words = check_mem(malloc((N + 1) * sizeof(char*))); + words[0] = NULL; + int curlen = 0; + + char word[BUFSIZ]; + while (fgets(word, sizeof(word), fp)) { + chomp(word); + char* text = state_words(word); + if (text != NULL) { + if (strlen(word) > curlen) { + for (int i = 0; i < N; i++) + free(words[i]); + N = 1; + words = check_mem(realloc(words, (N + 1) * sizeof(char*))); + words[0] = check_mem(strdup(word)); + words[1] = NULL; + curlen = strlen(word); + } + else if (strlen(word) == curlen) { + N++; + words = check_mem(realloc(words, (N + 1) * sizeof(char*))); + words[N - 1] = check_mem(strdup(word)); + words[N] = NULL; + } + free(text); + } + } + + fclose(fp); + + return words; +} + +int main(int argc, char* argv[]) { + if (argc != 2) { + fputs("usage: ch-2 dictionary.txt\n", stderr); + return EXIT_FAILURE; + } + + build_lookup_table(); + + char** words = search_words(argv[1]); + for (char** p = words; *p != NULL; p++) { + char* text = state_words(*p); + printf("%s = %s\n", *p, text); + free(text); + } + + free(words); +} diff --git a/challenge-014/paulo-custodio/perl/ch-1.pl b/challenge-014/paulo-custodio/perl/ch-1.pl index ff7c2ea8d0..38c78011dc 100644 --- a/challenge-014/paulo-custodio/perl/ch-1.pl +++ b/challenge-014/paulo-custodio/perl/ch-1.pl @@ -30,9 +30,11 @@ sub van_eck_iter { }; } +@ARGV==1 or die "usage: ch-1.pl N\n"; +my $N = shift; my $iter = van_eck_iter(); my $sep = ""; -for (0..96) { +for (1..$N) { print $sep, $iter->(); $sep = ", "; } diff --git a/challenge-014/paulo-custodio/perl/ch-2.pl b/challenge-014/paulo-custodio/perl/ch-2.pl index 6549b608a1..3e5b8b16f8 100644 --- a/challenge-014/paulo-custodio/perl/ch-2.pl +++ b/challenge-014/paulo-custodio/perl/ch-2.pl @@ -74,8 +74,11 @@ my $codes = join("|", @codes); # regex to match any codes my $regex = qr/^($codes)+$/i; # regex to match word composed of codes # find all words that match, save longest ones +@ARGV==1 or die "usage: ch-2.pl dictionary.txt\n"; +my $words = shift; + my @longest; -open(my $fh, "<", "words.txt") or die "open words.txt: $!\n"; +open(my $fh, "<", $words) or die "open $words: $!\n"; while (<$fh>) { chomp; next unless /$regex/; # filter words that match state codes diff --git a/challenge-014/paulo-custodio/python/ch-1.py b/challenge-014/paulo-custodio/python/ch-1.py index 6852909991..727c5b1529 100644 --- a/challenge-014/paulo-custodio/python/ch-1.py +++ b/challenge-014/paulo-custodio/python/ch-1.py @@ -35,6 +35,6 @@ for n in van_eck_iter(): output += sep + str(n) sep = ", " count += 1 - if count > 96: + if count >= 96: break print(output) diff --git a/challenge-014/paulo-custodio/python/ch-2.py b/challenge-014/paulo-custodio/python/ch-2.py index fd1890993e..03b7edc5f0 100644 --- a/challenge-014/paulo-custodio/python/ch-2.py +++ b/challenge-014/paulo-custodio/python/ch-2.py @@ -114,6 +114,6 @@ def word_to_states(word): states.append(us_states[cc]) return " + ".join(states) -words = longest_words(words_like_states(read_words(read_file("words.txt")))) +words = longest_words(words_like_states(read_words(read_file(sys.argv[1])))) for word in words: print(word+" = "+word_to_states(word)) diff --git a/challenge-014/paulo-custodio/t/test-1.yaml b/challenge-014/paulo-custodio/t/test-1.yaml index ebf698340d..7c15f5075f 100644 --- a/challenge-014/paulo-custodio/t/test-1.yaml +++ b/challenge-014/paulo-custodio/t/test-1.yaml @@ -1,5 +1,5 @@ - setup: cleanup: - args: 2019 + args: 96 input: - output: 0, 0, 1, 0, 2, 0, 2, 2, 1, 6, 0, 5, 0, 2, 6, 5, 4, 0, 5, 3, 0, 3, 2, 9, 0, 4, 9, 3, 6, 14, 0, 6, 3, 5, 15, 0, 5, 3, 5, 2, 17, 0, 6, 11, 0, 3, 8, 0, 3, 3, 1, 42, 0, 5, 15, 20, 0, 4, 32, 0, 3, 11, 18, 0, 4, 7, 0, 3, 7, 3, 2, 31, 0, 6, 31, 3, 6, 3, 2, 8, 33, 0, 9, 56, 0, 3, 8, 7, 19, 0, 5, 37, 0, 3, 8, 8, 1 + output: 0, 0, 1, 0, 2, 0, 2, 2, 1, 6, 0, 5, 0, 2, 6, 5, 4, 0, 5, 3, 0, 3, 2, 9, 0, 4, 9, 3, 6, 14, 0, 6, 3, 5, 15, 0, 5, 3, 5, 2, 17, 0, 6, 11, 0, 3, 8, 0, 3, 3, 1, 42, 0, 5, 15, 20, 0, 4, 32, 0, 3, 11, 18, 0, 4, 7, 0, 3, 7, 3, 2, 31, 0, 6, 31, 3, 6, 3, 2, 8, 33, 0, 9, 56, 0, 3, 8, 7, 19, 0, 5, 37, 0, 3, 8, 8 diff --git a/challenge-014/paulo-custodio/t/test-2.yaml b/challenge-014/paulo-custodio/t/test-2.yaml index c89ea9f41a..1b6246e24b 100644 --- a/challenge-014/paulo-custodio/t/test-2.yaml +++ b/challenge-014/paulo-custodio/t/test-2.yaml @@ -1,20 +1,7 @@ -- setup: 0==system("aspell -d en dump master | aspell -l en expand > words.txt") - cleanup: unlink("words.txt") - args: +- setup: + cleanup: + args: ../../data/dictionary.txt input: output: | - armorial = Arkansas + Missouri + Rhode Island + Alabama - calamine = California + Louisiana + Michigan + Nebraska - coalmine = Colorado + Alabama + Michigan + Nebraska - calamari = California + Louisiana + Massachusetts + Rhode Island - Concorde = Colorado + North Carolina + Oregon + Delaware - Ganymede = Georgia + New York + Maine + Delaware - landmine = Louisiana + North Dakota + Michigan + Nebraska - melamine = Maine + Louisiana + Michigan + Nebraska - moorland = Missouri + Oregon + Louisiana + North Dakota - malarial = Massachusetts + Louisiana + Rhode Island + Alabama - memorial = Maine + Missouri + Rhode Island + Alabama mainland = Massachusetts + Indiana + Louisiana + North Dakota - Mandarin = Massachusetts + North Dakota + Arkansas + Indiana - mandarin = Massachusetts + North Dakota + Arkansas + Indiana - mescalin = Maine + South Carolina + Alabama + Indiana + memorial = Maine + Missouri + Rhode Island + Alabama diff --git a/challenge-015/paulo-custodio/c/ch-1.c b/challenge-015/paulo-custodio/c/ch-1.c new file mode 100644 index 0000000000..82dc081d71 --- /dev/null +++ b/challenge-015/paulo-custodio/c/ch-1.c @@ -0,0 +1,97 @@ +/* +Challenge 015 + +Task #1 +Write a script to generate first 10 strong and weak prime numbers. + + For example, the nth prime number is represented by p(n). + + p(1) = 2 + p(2) = 3 + p(3) = 5 + p(4) = 7 + p(5) = 11 + + Strong Prime number p(n) when p(n) > [ p(n-1) + p(n+1) ] / 2 + Weak Prime number p(n) when p(n) < [ p(n-1) + p(n+1) ] / 2 +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <stdbool.h> + +void* check_mem(void* p) { + if (!p) { + fputs("Out of memory", stderr); + exit(EXIT_FAILURE); + } + return p; +} + +bool is_prime(int n) { + if (n <= 1) + return false; + if (n <= 3) + return true; + if ((n % 2) == 0 || (n % 3) == 0) + return false; + for (int i = 5; i * i <= n; i += 6) + if ((n % i) == 0 || (n % (i + 2)) == 0) + return false; + return true; +} + +int next_prime(int n) { + if (n <= 1) + return 2; + do { + n++; + } while (!is_prime(n)); + return n; +} + +int* strong_weak_primes(int N, bool want_strong) { + int* primes = check_mem(malloc(N * sizeof(int))); + int p1 = 2, p2 = 3, p3 = 5; + for (int i = 0; i < N; ) { + float avg = ((float)p1+p3)/2; + if (want_strong) { + if (p2 > avg) + primes[i++] = p2; + } + else { + if ((float)p2 < avg) + primes[i++] = p2; + } + + // next prime + p1 = p2; p2 = p3; p3 = next_prime(p2); + } + return primes; +} + +void print_list(int* nums, int N) { + const char* sep = ""; + for (int i = 0; i < N; i++) { + printf("%s%d", sep, nums[i]); + sep = ", "; + } +} + +int main (int argc, char* argv[]) { + int N = 10; + if (argc == 2) + N = atoi(argv[1]); + + int* primes = strong_weak_primes(N, true); + printf("Strong Prime: "); + print_list(primes, N); + printf("\n"); + free(primes); + + primes = strong_weak_primes(N, false); + printf("Weak Prime: "); + print_list(primes, N); + printf("\n"); + free(primes); +} diff --git a/challenge-015/paulo-custodio/c/ch-2.c b/challenge-015/paulo-custodio/c/ch-2.c new file mode 100644 index 0000000000..4265a8c456 --- /dev/null +++ b/challenge-015/paulo-custodio/c/ch-2.c @@ -0,0 +1,58 @@ +/* +Challenge 015 + +Task #2 +Write a script to implement Vigenère cipher. The script should be able encode +and decode. Checkout wiki page for more information. +*/ + +#include <ctype.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#define LETTERS ('Z'-'A'+1) +#define TO_LETTER(a) ((a)+'A') +#define TO_CODE(a) (toupper(a)-'A') + +#define ENCODE 1 +#define DECODE -1 + +void* check_mem(void* p) { + if (!p) { + fputs("out of memory", stderr); + exit(EXIT_FAILURE); + } + return p; +} + +char* vigenere(const char* text, const char* key, int encode) { + char* encoded = check_mem(strdup(text)); + const char* p = text; + const char* k = key; + char* q = encoded; + while (*p) { + if (isalpha(*p)) + *q++ = TO_LETTER((TO_CODE(*p++)+LETTERS+encode*TO_CODE(*k))%LETTERS); + if (*++k == '\0') + k = key; + } + *q++ = '\0'; + return encoded; +} + +int main(int argc, char* argv[]) { + if (argc != 4) { + fputs("usage: ch-2 encode|decode key text", stderr); + return EXIT_FAILURE; + } + + int encode = (strcmp(argv[1], "encode") == 0) ? ENCODE : DECODE; + const char* key = argv[2]; + const char* text = argv[3]; + + char* encoded = vigenere(text, key, encode); + printf("%s\n", encoded); + + free(encoded); +} diff --git a/challenge-016/paulo-custodio/c/ch-1.c b/challenge-016/paulo-custodio/c/ch-1.c new file mode 100644 index 0000000000..5ddb957303 --- /dev/null +++ b/challenge-016/paulo-custodio/c/ch-1.c @@ -0,0 +1,49 @@ +/* +Challenge 016 + +Task #1 +Pythagoras Pie Puzzle, proposed by Jo Christian Oterhals. + +At a party a pie is to be shared by 100 guest. The first guest gets 1% of the +pie, the second guest gets 2% of the remaining pie, the third gets 3% of the +remaining pie, the fourth gets 4% and so on. + +Write a script that figures out which guest gets the largest piece of pie. +*/ + +#include <stdio.h> +#include <stdlib.h> + +#define NUM_SLICES 100 + +struct slice { + int guest; + double portion; +}; + +int compare(const void* a, const void* b) { + double a_portion = ((struct slice*)a)->portion; + double b_portion = ((struct slice*)b)->portion; + return (a_portion == b_portion) ? 0 : (a_portion < b_portion) ? 1 : -1; +} + +struct slice pie_puzzle() { + struct slice slices[NUM_SLICES]; + + double pie = 1.0; + for (int i = 1; i <= NUM_SLICES; i++) { + slices[i - 1].guest = i; + slices[i - 1].portion = (double)i / 100.0 * pie; + pie -= slices[i - 1].portion; + } + + qsort(slices, NUM_SLICES, sizeof(struct slice), compare); + + return slices[0]; +} + +int main() { + struct slice result = pie_puzzle(); + printf("Guest %d gets %.4f%% of the pie.\n", + result.guest, 100.0 * result.portion); +} diff --git a/challenge-016/paulo-custodio/c/ch-2.c b/challenge-016/paulo-custodio/c/ch-2.c new file mode 100644 index 0000000000..5e9630133b --- /dev/null +++ b/challenge-016/paulo-custodio/c/ch-2.c @@ -0,0 +1,134 @@ +/* +Challenge 016 + +Task #2 +Write a script to validate a given bitcoin address. Most Bitcoin addresses +are 34 characters. They consist of random digits and uppercase and lowercase +letters, with the exception that the uppercase letter “O”, uppercase letter “I”, +lowercase letter “l”, and the number “0” are never used to prevent visual +ambiguity. A bitcoin address encodes 25 bytes. The last four bytes are a +checksum check. They are the first four bytes of a double SHA-256 digest +of the previous 21 bytes. For more information, please refer wiki page. +Here are some valid bitcoin addresses: + + 1BvBMSEYstWetqTFn5Au4m4GFg7xJaNVN2 + 3J98t1WpEZ73CNmQviecrnyiWrnqRhWNLy +*/ + + +#include <assert.h> +#include <ctype.h> +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <stdbool.h> +#include <string.h> + +// uses sha256 from https://github.com/B-Con/crypto-algorithms +// to integrate with test infrastructure needs one single source ch-2.c +// therefore include sha256.c +#include "sha256.c" + +#define BASE58 58 +#define BTC_ADDR_SIZE 25 +#define CHECKSUM_SIZE 4 + +const char* B58_DIGITS = "123456789" \ +"ABCDEFGHJKLMNPQRSTUVWXYZ" \ +"abcdefghijkmnopqrstuvwxyz"; + +void* check_mem(void* p) { + if (!p) { + fputs("out of memory", stderr); + exit(EXIT_FAILURE); + } + return p; +} + +int decode_b58_digit(char c) { + if (!isalnum(c)) + return -1; + const char* p = strchr(B58_DIGITS, c); + if (p == NULL) + return -1; + else + return (int)(p - B58_DIGITS); +} + +bool decode_b58(uint8_t* result, size_t result_size, const char* code) { + int* values = check_mem(calloc(result_size, sizeof(int))); + + // decode each digit + for (const char* p = code; *p; p++) { + int digit = decode_b58_digit(*p); + if (digit < 0) { + free(values); + return false; + } + + // multiply all bytes by base and add digit + for (int i = (int)result_size - 1; i >= 0; i--) + values[i] *= BASE58; + + int carry = digit; + for (int i = (int)result_size - 1; i >= 0; i--) { + values[i] += carry; + carry = 0; + + if (values[i] > 0xff) { + carry = values[i] >> 8; + values[i] &= 0xff; + } + } + + if (carry != 0) { // size too short for value + free(values); + return false; + } + } + + // convert values to bytes + for (int i = 0; i < result_size; i++) + result[i] = (uint8_t)values[i]; + + free(values); + return true; +} + +bool is_btc_address_valid(const char* str) { + // check prefix + if (str[0] != '1' && str[0] != '3' && strncmp(str, "bc1", 3) != 0) + return false; + + // decode address + uint8_t addr[BTC_ADDR_SIZE]; + if (!decode_b58(addr, BTC_ADDR_SIZE, str)) + return false; + + // compute checksum + uint8_t buf1[SHA256_BLOCK_SIZE]; + SHA256_CTX ctx1; + sha256_init(&ctx1); + sha256_update(&ctx1, addr, BTC_ADDR_SIZE - CHECKSUM_SIZE); + sha256_final(&ctx1, buf1); + + uint8_t buf2[SHA256_BLOCK_SIZE]; + SHA256_CTX ctx2; + sha256_init(&ctx2); + sha256_update(&ctx2, buf1, SHA256_BLOCK_SIZE); + sha256_final(&ctx2, buf2); + + if (memcmp(buf2, addr + BTC_ADDR_SIZE - CHECKSUM_SIZE, CHECKSUM_SIZE) == 0) + return true; + else + return false; +} + +int main(int argc, char* argv[]) { + if (argc != 2) { + fputs("usage: ch-2 address", stderr); + return EXIT_FAILURE; + } + + printf("%d\n", is_btc_address_valid(argv[1]) ? 1 : 0); +} diff --git a/challenge-016/paulo-custodio/c/sha256.README.md b/challenge-016/paulo-custodio/c/sha256.README.md new file mode 100644 index 0000000000..cfaf542323 --- /dev/null +++ b/challenge-016/paulo-custodio/c/sha256.README.md @@ -0,0 +1,17 @@ +crypto-algorithms +================= + + +About +--- +These are basic implementations of standard cryptography algorithms, written by Brad Conte (brad@bradconte.com) from scratch and without any cross-licensing. They exist to provide publically accessible, restriction-free implementations of popular cryptographic algorithms, like AES and SHA-1. These are primarily intended for educational and pragmatic purposes (such as comparing a specification to actual implementation code, or for building an internal application that computes test vectors for a product). The algorithms have been tested against standard test vectors. + +This code is released into the public domain free of any restrictions. The author requests acknowledgement if the code is used, but does not require it. This code is provided free of any liability and without any quality claims by the author. + +Note that these are *not* cryptographically secure implementations. They have no resistence to side-channel attacks and should not be used in contexts that need cryptographically secure implementations. + +These algorithms are not optimized for speed or space. They are primarily designed to be easy to read, although some basic optimization techniques have been employed. + +Building +--- +The source code for each algorithm will come in a pair of a source code file and a header file. There should be no inter-header file dependencies, no additional libraries, no platform-specific header files, or any other complicating matters. Compiling them should be as easy as adding the relevent source code to the project. diff --git a/challenge-016/paulo-custodio/c/sha256.c b/challenge-016/paulo-custodio/c/sha256.c new file mode 100644 index 0000000000..8fdcb6f5ff --- /dev/null +++ b/challenge-016/paulo-custodio/c/sha256.c @@ -0,0 +1,158 @@ +/********************************************************************* +* Filename: sha256.c +* Author: Brad Conte (brad AT bradconte.com) +* Copyright: +* Disclaimer: This code is presented "as is" without any guarantees. +* Details: Implementation of the SHA-256 hashing algorithm. + SHA-256 is one of the three algorithms in the SHA2 + specification. The others, SHA-384 and SHA-512, are not + offered in this implementation. + Algorithm specification can be found here: + * http://csrc.nist.gov/publications/fips/fips180-2/fips180-2withchangenotice.pdf + This implementation uses little endian byte order. +*********************************************************************/ + +/*************************** HEADER FILES ***************************/ +#include <stdlib.h> +#include <memory.h> +#include "sha256.h" + +/****************************** MACROS ******************************/ +#define ROTLEFT(a,b) (((a) << (b)) | ((a) >> (32-(b)))) +#define ROTRIGHT(a,b) (((a) >> (b)) | ((a) << (32-(b)))) + +#define CH(x,y,z) (((x) & (y)) ^ (~(x) & (z))) +#define MAJ(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) +#define EP0(x) (ROTRIGHT(x,2) ^ ROTRIGHT(x,13) ^ ROTRIGHT(x,22)) +#define EP1(x) (ROTRIGHT(x,6) ^ ROTRIGHT(x,11) ^ ROTRIGHT(x,25)) +#define SIG0(x) (ROTRIGHT(x,7) ^ ROTRIGHT(x,18) ^ ((x) >> 3)) +#define SIG1(x) (ROTRIGHT(x,17) ^ ROTRIGHT(x,19) ^ ((x) >> 10)) + +/**************************** VARIABLES *****************************/ +static const WORD k[64] = { + 0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5,0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5, + 0xd807aa98,0x12835b01,0x243185be,0x550c7dc3,0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174, + 0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc,0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da, + 0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7,0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967, + 0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13,0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85, + 0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3,0xd192e819,0xd6990624,0xf40e3585,0x106aa070, + 0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5,0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3, + 0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208,0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2 +}; + +/*********************** FUNCTION DEFINITIONS ***********************/ +void sha256_transform(SHA256_CTX *ctx, const BYTE data[]) +{ + WORD a, b, c, d, e, f, g, h, i, j, t1, t2, m[64]; + + for (i = 0, j = 0; i < 16; ++i, j += 4) + m[i] = (data[j] << 24) | (data[j + 1] << 16) | (data[j + 2] << 8) | (data[j + 3]); + for ( ; i < 64; ++i) + m[i] = SIG1(m[i - 2]) + m[i - 7] + SIG0(m[i - 15]) + m[i - 16]; + + a = ctx->state[0]; + b = ctx->state[1]; + c = ctx->state[2]; + d = ctx->state[3]; + e = ctx->state[4]; + f = ctx->state[5]; + g = ctx->state[6]; + h = ctx->state[7]; + + for (i = 0; i < 64; ++i) { + t1 = h + EP1(e) + CH(e,f,g) + k[i] + m[i]; + t2 = EP0(a) + MAJ(a,b,c); + h = g; + g = f; + f = e; + e = d + t1; + d = c; + c = b; + b = a; + a = t1 + t2; + } + + ctx->state[0] += a; + ctx->state[1] += b; + ctx->state[2] += c; + ctx->state[3] += d; + ctx->state[4] += e; + ctx->state[5] += f; + ctx->state[6] += g; + ctx->state[7] += h |
