From 244d2de211875bd393c0d38225f77f31a18e6c9c Mon Sep 17 00:00:00 2001 From: Rajasree2004 Date: Sat, 25 Oct 2025 16:14:03 +0530 Subject: [PATCH 1/7] Add Merkle Tree construction and verification algorithm --- blockchain/merkle_tree.py | 94 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 blockchain/merkle_tree.py diff --git a/blockchain/merkle_tree.py b/blockchain/merkle_tree.py new file mode 100644 index 000000000000..32222723c15d --- /dev/null +++ b/blockchain/merkle_tree.py @@ -0,0 +1,94 @@ +""" +Merkle Tree Construction and Verification + +This module implements the construction of a Merkle Tree and +verification of inclusion proofs for blockchain data integrity. + +Each leaf is a SHA-256 hash of a transaction, and internal nodes are +computed by hashing the concatenation of their child nodes. + +References: +https://en.wikipedia.org/wiki/Merkle_tree +""" + +import hashlib + + +def sha256(data: str) -> str: + """Compute SHA-256 hash of a string.""" + return hashlib.sha256(data.encode()).hexdigest() + + +def build_merkle_tree(leaves: list[str]) -> list[list[str]]: + """ + Build a Merkle Tree from the given leaf nodes. + + Args: + leaves: List of data strings (transactions). + + Returns: + A list of lists representing tree levels, + with the last level containing the Merkle root. + + >>> len(build_merkle_tree(["a", "b", "c", "d"])[-1][0]) + 64 + """ + if not leaves: + raise ValueError("Leaf list cannot be empty.") + + current_level = [sha256(x) for x in leaves] + tree = [current_level] + + while len(current_level) > 1: + next_level = [] + for i in range(0, len(current_level), 2): + left = current_level[i] + right = current_level[i + 1] if i + 1 < len(current_level) else left + next_level.append(sha256(left + right)) + current_level = next_level + tree.append(current_level) + + return tree + + +def merkle_root(leaves: list[str]) -> str: + """ + Return the Merkle root hash for a given list of data. + + >>> r = merkle_root(["tx1", "tx2", "tx3"]) + >>> isinstance(r, str) + True + """ + return build_merkle_tree(leaves)[-1][0] + + +def verify_proof(leaf: str, proof: list[str], root: str) -> bool: + """ + Verify inclusion of a leaf using a Merkle proof. + + Args: + leaf: Original data string. + proof: List of sibling hashes up the path. + root: Expected Merkle root hash. + + Returns: + True if proof is valid, else False. + + >>> data = ["a", "b", "c", "d"] + >>> tree = build_merkle_tree(data) + >>> root = tree[-1][0] + >>> leaf = "a" + >>> proof = [sha256("b"), sha256(sha256("c") + sha256("d"))] + >>> verify_proof(leaf, proof, root) + True + """ + computed_hash = sha256(leaf) + for sibling in proof: + combined = sha256(computed_hash + sibling) + computed_hash = combined + return computed_hash == root + + +if __name__ == "__main__": + import doctest + doctest.testmod() From 825b730384f5812760b0933119f65cc6611ad5a4 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sat, 25 Oct 2025 10:48:32 +0000 Subject: [PATCH 2/7] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- blockchain/merkle_tree.py | 1 + 1 file changed, 1 insertion(+) diff --git a/blockchain/merkle_tree.py b/blockchain/merkle_tree.py index 32222723c15d..68ea280647bc 100644 --- a/blockchain/merkle_tree.py +++ b/blockchain/merkle_tree.py @@ -91,4 +91,5 @@ def verify_proof(leaf: str, proof: list[str], root: str) -> bool: if __name__ == "__main__": import doctest + doctest.testmod() From ee5b1bf171faf5ce4433b0cb5ea7091bdfef58c2 Mon Sep 17 00:00:00 2001 From: Rajasree2004 Date: Sat, 25 Oct 2025 16:21:52 +0530 Subject: [PATCH 3/7] Added doctest to sha256 function in merkle tree --- blockchain/merkle_tree.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/blockchain/merkle_tree.py b/blockchain/merkle_tree.py index 32222723c15d..32ded6118df1 100644 --- a/blockchain/merkle_tree.py +++ b/blockchain/merkle_tree.py @@ -15,7 +15,19 @@ def sha256(data: str) -> str: - """Compute SHA-256 hash of a string.""" + """ + Compute the SHA-256 hash of the given string. + + Args: + data (str): Input string. + + Returns: + str: Hexadecimal SHA-256 hash of the input. + + Example: + >>> sha256("abc") + 'ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad' + """ return hashlib.sha256(data.encode()).hexdigest() From 65c0e39bcdeb770cd22e7cc22175c4725152c93c Mon Sep 17 00:00:00 2001 From: Rajasree2004 Date: Sat, 25 Oct 2025 16:38:58 +0530 Subject: [PATCH 4/7] Add Simon's Algorithm Simulation' --- quantum/simons_algorithm.py | 77 +++++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 quantum/simons_algorithm.py diff --git a/quantum/simons_algorithm.py b/quantum/simons_algorithm.py new file mode 100644 index 000000000000..809c2e98f80c --- /dev/null +++ b/quantum/simons_algorithm.py @@ -0,0 +1,77 @@ +""" +Simon's Algorithm (Classical Simulation) + +Simon's algorithm finds a hidden bitstring s such that +f(x) = f(y) if and only if x XOR y = s. + +Here we simulate the mapping behavior classically to +illustrate how the hidden period can be discovered by +analyzing collisions in f(x). + +References: +https://en.wikipedia.org/wiki/Simon's_problem +""" + +from collections.abc import Callable +from itertools import product + + +def xor_bits(a: list[int], b: list[int]) -> list[int]: + """ + Return the bitwise XOR of two equal-length bit lists. + + >>> xor_bits([1, 0, 1], [1, 1, 0]) + [0, 1, 1] + """ + if len(a) != len(b): + raise ValueError("Bit lists must be of equal length.") + return [x ^ y for x, y in zip(a, b)] + + +def simons_algorithm(f: Callable[[list[int]], list[int]], n: int) -> list[int]: + + """ + Simulate Simon's algorithm classically to find the hidden bitstring s. + + Args: + f: A function mapping n-bit input to n-bit output. + n: Number of bits in the input. + + Returns: + The hidden bitstring s as a list of bits. + + >>> # Example with hidden bitstring s = [1, 0, 1] + >>> s = [1, 0, 1] + >>> def f(x): + ... mapping = { + ... (0,0,0): (1,1,0), + ... (1,0,1): (1,1,0), + ... (0,0,1): (0,1,1), + ... (1,0,0): (0,1,1), + ... (0,1,0): (1,0,1), + ... (1,1,1): (1,0,1), + ... (0,1,1): (0,0,0), + ... (1,1,0): (0,0,0), + ... } + ... return mapping[tuple(x)] + >>> simons_algorithm(f, 3) + [1, 0, 1] + """ + mapping: dict[tuple[int, ...], tuple[int, ...]] = {} + inputs = list(product([0, 1], repeat=n)) + + for x in inputs: + fx = tuple(f(list(x))) + if fx in mapping: + y = mapping[fx] + return xor_bits(list(x), list(y)) + mapping[fx] = x + + # If no collision found, function might be constant + return [0] * n + + +if __name__ == "__main__": + import doctest + + doctest.testmod() From ed920a386e7e846b87243b735a5b65a1efd01893 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sat, 25 Oct 2025 11:11:00 +0000 Subject: [PATCH 5/7] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- quantum/simons_algorithm.py | 1 - 1 file changed, 1 deletion(-) diff --git a/quantum/simons_algorithm.py b/quantum/simons_algorithm.py index 809c2e98f80c..025ec6d71cf3 100644 --- a/quantum/simons_algorithm.py +++ b/quantum/simons_algorithm.py @@ -29,7 +29,6 @@ def xor_bits(a: list[int], b: list[int]) -> list[int]: def simons_algorithm(f: Callable[[list[int]], list[int]], n: int) -> list[int]: - """ Simulate Simon's algorithm classically to find the hidden bitstring s. From 7b90b1c49f809b5c60c4190d5b85fb2b6e4b9327 Mon Sep 17 00:00:00 2001 From: Rajasree2004 Date: Sat, 25 Oct 2025 16:46:25 +0530 Subject: [PATCH 6/7] Add Parameter Rename to Simon's Algorithm' --- quantum/simons_algorithm.py | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/quantum/simons_algorithm.py b/quantum/simons_algorithm.py index 025ec6d71cf3..8565a8896a4f 100644 --- a/quantum/simons_algorithm.py +++ b/quantum/simons_algorithm.py @@ -2,11 +2,11 @@ Simon's Algorithm (Classical Simulation) Simon's algorithm finds a hidden bitstring s such that -f(x) = f(y) if and only if x XOR y = s. +f(input_bits) = f(other_bits) if and only if input_bits XOR other_bits = s. Here we simulate the mapping behavior classically to illustrate how the hidden period can be discovered by -analyzing collisions in f(x). +analyzing collisions in f(input_bits). References: https://en.wikipedia.org/wiki/Simon's_problem @@ -16,32 +16,32 @@ from itertools import product -def xor_bits(a: list[int], b: list[int]) -> list[int]: +def xor_bits(bits1: list[int], bits2: list[int]) -> list[int]: """ Return the bitwise XOR of two equal-length bit lists. >>> xor_bits([1, 0, 1], [1, 1, 0]) [0, 1, 1] """ - if len(a) != len(b): + if len(bits1) != len(bits2): raise ValueError("Bit lists must be of equal length.") - return [x ^ y for x, y in zip(a, b)] + return [x ^ y for x, y in zip(bits1, bits2)] -def simons_algorithm(f: Callable[[list[int]], list[int]], n: int) -> list[int]: +def simons_algorithm(f: Callable[[list[int]], list[int]], num_bits: int) -> list[int]: """ Simulate Simon's algorithm classically to find the hidden bitstring s. Args: f: A function mapping n-bit input to n-bit output. - n: Number of bits in the input. + num_bits: Number of bits in the input. Returns: The hidden bitstring s as a list of bits. >>> # Example with hidden bitstring s = [1, 0, 1] >>> s = [1, 0, 1] - >>> def f(x): + >>> def f(input_bits): ... mapping = { ... (0,0,0): (1,1,0), ... (1,0,1): (1,1,0), @@ -52,22 +52,22 @@ def simons_algorithm(f: Callable[[list[int]], list[int]], n: int) -> list[int]: ... (0,1,1): (0,0,0), ... (1,1,0): (0,0,0), ... } - ... return mapping[tuple(x)] + ... return mapping[tuple(input_bits)] >>> simons_algorithm(f, 3) [1, 0, 1] """ mapping: dict[tuple[int, ...], tuple[int, ...]] = {} - inputs = list(product([0, 1], repeat=n)) + inputs = list(product([0, 1], repeat=num_bits)) - for x in inputs: - fx = tuple(f(list(x))) + for bits in inputs: + fx = tuple(f(list(bits))) if fx in mapping: - y = mapping[fx] - return xor_bits(list(x), list(y)) - mapping[fx] = x + prev_bits = mapping[fx] + return xor_bits(list(bits), list(prev_bits)) + mapping[fx] = bits # If no collision found, function might be constant - return [0] * n + return [0] * num_bits if __name__ == "__main__": From 90618a20db32ab02620254863e41918ce07634e5 Mon Sep 17 00:00:00 2001 From: Rajasree2004 Date: Sat, 25 Oct 2025 16:52:04 +0530 Subject: [PATCH 7/7] Add Parameter Rename to Simon's Algorithm' --- quantum/simons_algorithm.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/quantum/simons_algorithm.py b/quantum/simons_algorithm.py index 8565a8896a4f..816a184af02f 100644 --- a/quantum/simons_algorithm.py +++ b/quantum/simons_algorithm.py @@ -28,12 +28,14 @@ def xor_bits(bits1: list[int], bits2: list[int]) -> list[int]: return [x ^ y for x, y in zip(bits1, bits2)] -def simons_algorithm(f: Callable[[list[int]], list[int]], num_bits: int) -> list[int]: +def simons_algorithm( + hidden_function: Callable[[list[int]], list[int]], num_bits: int +) -> list[int]: """ Simulate Simon's algorithm classically to find the hidden bitstring s. Args: - f: A function mapping n-bit input to n-bit output. + hidden_function: A function mapping n-bit input to n-bit output. num_bits: Number of bits in the input. Returns: @@ -41,7 +43,7 @@ def simons_algorithm(f: Callable[[list[int]], list[int]], num_bits: int) -> list >>> # Example with hidden bitstring s = [1, 0, 1] >>> s = [1, 0, 1] - >>> def f(input_bits): + >>> def hidden_function(input_bits): ... mapping = { ... (0,0,0): (1,1,0), ... (1,0,1): (1,1,0), @@ -53,14 +55,14 @@ def simons_algorithm(f: Callable[[list[int]], list[int]], num_bits: int) -> list ... (1,1,0): (0,0,0), ... } ... return mapping[tuple(input_bits)] - >>> simons_algorithm(f, 3) + >>> simons_algorithm(hidden_function, 3) [1, 0, 1] """ mapping: dict[tuple[int, ...], tuple[int, ...]] = {} inputs = list(product([0, 1], repeat=num_bits)) for bits in inputs: - fx = tuple(f(list(bits))) + fx = tuple(hidden_function(list(bits))) if fx in mapping: prev_bits = mapping[fx] return xor_bits(list(bits), list(prev_bits))