mirror of
https://github.com/3b1b/manim.git
synced 2025-08-01 17:29:06 +08:00
Up to IntroduceBlockChain in crypto
This commit is contained in:
908
crypto.py
908
crypto.py
@ -28,6 +28,9 @@ from camera import Camera
|
|||||||
from mobject.svg_mobject import *
|
from mobject.svg_mobject import *
|
||||||
from mobject.tex_mobject import *
|
from mobject.tex_mobject import *
|
||||||
|
|
||||||
|
from hashlib import sha256
|
||||||
|
import binascii
|
||||||
|
|
||||||
#force_skipping
|
#force_skipping
|
||||||
#revert_to_original_skipping_status
|
#revert_to_original_skipping_status
|
||||||
|
|
||||||
@ -38,6 +41,30 @@ def get_cursive_name(name):
|
|||||||
result.set_stroke(width = 0.5)
|
result.set_stroke(width = 0.5)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
def sha256_bit_string(message):
|
||||||
|
hexdigest = sha256(message).hexdigest()
|
||||||
|
return bin(int(hexdigest, 16))[2:]
|
||||||
|
|
||||||
|
def sha256_tex_mob(message, n_forced_start_zeros = 0):
|
||||||
|
line = TexMobject("0"*32)
|
||||||
|
pre_result = VGroup(*[
|
||||||
|
line.copy() for row in range(8)
|
||||||
|
])
|
||||||
|
pre_result.arrange_submobjects(DOWN, buff = SMALL_BUFF)
|
||||||
|
result = VGroup(*it.chain(*pre_result))
|
||||||
|
result.scale(0.7)
|
||||||
|
|
||||||
|
true_bit_string = sha256_bit_string(message)
|
||||||
|
n = n_forced_start_zeros
|
||||||
|
bit_string = "0"*n + true_bit_string[n:]
|
||||||
|
for i, (bit, part) in enumerate(zip(bit_string, result)):
|
||||||
|
if bit == "1":
|
||||||
|
one = TexMobject("1")[0]
|
||||||
|
one.replace(part, dim_to_match = 1)
|
||||||
|
result.submobjects[i] = one
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
class TenDollarBill(VGroup):
|
class TenDollarBill(VGroup):
|
||||||
CONFIG = {
|
CONFIG = {
|
||||||
"color" : GREEN,
|
"color" : GREEN,
|
||||||
@ -348,6 +375,7 @@ class LedgerScene(PiCreatureScene):
|
|||||||
])
|
])
|
||||||
labels = VGroup(*[pi.label for pi in creatures])
|
labels = VGroup(*[pi.label for pi in creatures])
|
||||||
self.network = VGroup(creatures, labels, lines)
|
self.network = VGroup(creatures, labels, lines)
|
||||||
|
self.network.lines = lines
|
||||||
return self.network
|
return self.network
|
||||||
|
|
||||||
def create_pi_creatures(self):
|
def create_pi_creatures(self):
|
||||||
@ -2009,19 +2037,873 @@ class YouListeningToBroadcasts(LedgerScene):
|
|||||||
)
|
)
|
||||||
self.dither()
|
self.dither()
|
||||||
|
|
||||||
|
class AskWhatToAddToProtocol(InitialProtocol):
|
||||||
|
def construct(self):
|
||||||
|
self.add_title()
|
||||||
|
items = VGroup(*map(self.get_new_item, [
|
||||||
|
"Broadcast transactions",
|
||||||
|
"Only accept signed transactions",
|
||||||
|
"No overspending",
|
||||||
|
] + [""]*6))
|
||||||
|
brace = Brace(VGroup(*items[3:]), LEFT)
|
||||||
|
question = TextMobject("What to \\\\ add here?")
|
||||||
|
question.highlight(RED)
|
||||||
|
question.scale(1.5)
|
||||||
|
brace.highlight(RED)
|
||||||
|
question.next_to(brace, LEFT)
|
||||||
|
|
||||||
|
self.add(*items[:3])
|
||||||
|
self.play(GrowFromCenter(brace))
|
||||||
|
self.play(Write(question))
|
||||||
|
self.dither()
|
||||||
|
|
||||||
|
class TrustComputationalWork(DistributedLedgerScene):
|
||||||
|
def construct(self):
|
||||||
|
self.add_ledger()
|
||||||
|
self.show_work()
|
||||||
|
|
||||||
|
def add_ledger(self):
|
||||||
|
ledgers = self.get_distributed_ledgers()
|
||||||
|
ledger = ledgers[0]
|
||||||
|
ledger.scale(3)
|
||||||
|
ledger[1].scale_in_place(2./3)
|
||||||
|
ledger.center().to_edge(UP).shift(4*LEFT)
|
||||||
|
plus = TexMobject("+")
|
||||||
|
plus.next_to(ledger, RIGHT)
|
||||||
|
|
||||||
|
self.add(ledger, plus)
|
||||||
|
self.ledger = ledger
|
||||||
|
self.plus = plus
|
||||||
|
|
||||||
|
def show_work(self):
|
||||||
|
zeros = TexMobject("0"*32)
|
||||||
|
zeros.next_to(self.plus, RIGHT)
|
||||||
|
brace = Brace(zeros, DOWN)
|
||||||
|
words = brace.get_text("Computational work")
|
||||||
|
self.add(brace, words)
|
||||||
|
|
||||||
|
for n in range(2**12):
|
||||||
|
binary = bin(n)[2:]
|
||||||
|
for i, bit_str in enumerate(reversed(binary)):
|
||||||
|
curr_bit = zeros.submobjects[-i-1]
|
||||||
|
new_bit = TexMobject(bit_str)
|
||||||
|
new_bit.replace(curr_bit, dim_to_match = 1)
|
||||||
|
if bit_str == "1":
|
||||||
|
new_bit.highlight(YELLOW)
|
||||||
|
zeros.submobjects[-i-1] = new_bit
|
||||||
|
self.remove(curr_bit)
|
||||||
|
self.add(zeros)
|
||||||
|
self.dither(1./30)
|
||||||
|
|
||||||
|
class TrustComputationalWorkSupplement(Scene):
|
||||||
|
def construct(self):
|
||||||
|
words = TextMobject(
|
||||||
|
"Main tool: ", "Cryptographic hash functions"
|
||||||
|
)
|
||||||
|
words[1].highlight(YELLOW)
|
||||||
|
self.add(words[0])
|
||||||
|
self.play(Write(words[1]))
|
||||||
|
self.dither()
|
||||||
|
|
||||||
|
class ThisIsWellIntoTheWeeds(TeacherStudentsScene):
|
||||||
|
def construct(self):
|
||||||
|
idea = TextMobject("Proof of work")
|
||||||
|
idea.move_to(self.teacher.get_corner(UP+LEFT))
|
||||||
|
idea.shift(MED_LARGE_BUFF*UP)
|
||||||
|
idea.save_state()
|
||||||
|
lightbulb = Lightbulb()
|
||||||
|
lightbulb.next_to(idea, UP)
|
||||||
|
idea.shift(DOWN)
|
||||||
|
idea.set_fill(opacity = 0)
|
||||||
|
|
||||||
|
self.teacher_says(
|
||||||
|
"We're well into \\\\ the weeds now",
|
||||||
|
target_mode = "sassy",
|
||||||
|
added_anims = [
|
||||||
|
ApplyMethod(pi.change, mode)
|
||||||
|
for pi, mode in zip(self.students, [
|
||||||
|
"hooray", "sad", "erm"
|
||||||
|
])
|
||||||
|
],
|
||||||
|
)
|
||||||
|
self.dither()
|
||||||
|
self.play(
|
||||||
|
idea.restore,
|
||||||
|
RemovePiCreatureBubble(
|
||||||
|
self.teacher, target_mode = "hooray",
|
||||||
|
look_at_arg = lightbulb
|
||||||
|
),
|
||||||
|
)
|
||||||
|
self.change_student_modes(
|
||||||
|
*["pondering"]*3,
|
||||||
|
added_anims = [LaggedStart(FadeIn, lightbulb)]
|
||||||
|
)
|
||||||
|
self.play(LaggedStart(
|
||||||
|
ApplyMethod, lightbulb,
|
||||||
|
lambda b : (b.highlight, YELLOW_A),
|
||||||
|
rate_func = there_and_back
|
||||||
|
))
|
||||||
|
self.dither(2)
|
||||||
|
|
||||||
|
class IntroduceSHA256(Scene):
|
||||||
|
def construct(self):
|
||||||
|
self.introduce_evaluation()
|
||||||
|
self.inverse_function_question()
|
||||||
|
self.issue_challenge()
|
||||||
|
self.shift_everything_down()
|
||||||
|
self.guess_and_check()
|
||||||
|
|
||||||
|
def introduce_evaluation(self):
|
||||||
|
messages = [
|
||||||
|
"3Blue1Brown",
|
||||||
|
"3Blue1Crown",
|
||||||
|
"Mathologer",
|
||||||
|
"Infinite Series",
|
||||||
|
"Numberphile",
|
||||||
|
"Welch Labs",
|
||||||
|
"3Blue1Brown",
|
||||||
|
]
|
||||||
|
groups = VGroup()
|
||||||
|
for message in messages:
|
||||||
|
lhs = TextMobject(
|
||||||
|
"SHA256", "(``", message, "'') =",
|
||||||
|
arg_separator = ""
|
||||||
|
)
|
||||||
|
lhs.highlight_by_tex(message, BLUE)
|
||||||
|
digest = sha256_tex_mob(message)
|
||||||
|
digest.next_to(lhs, RIGHT)
|
||||||
|
group = VGroup(lhs, digest)
|
||||||
|
group.to_corner(UP+RIGHT)
|
||||||
|
group.shift(MED_LARGE_BUFF*DOWN)
|
||||||
|
groups.add(group)
|
||||||
|
|
||||||
|
group = groups[0]
|
||||||
|
lhs, digest = group
|
||||||
|
sha, lp, message, lp = lhs
|
||||||
|
sha_brace = Brace(sha, UP)
|
||||||
|
message_brace = Brace(message, DOWN)
|
||||||
|
digest_brace = Brace(digest, DOWN)
|
||||||
|
sha_text = sha_brace.get_text("", "Hash function")
|
||||||
|
sha_text.highlight(YELLOW)
|
||||||
|
message_text = message_brace.get_text("Message/file")
|
||||||
|
message_text.highlight(BLUE)
|
||||||
|
digest_text = digest_brace.get_text("``Hash'' or ``Digest''")
|
||||||
|
brace_text_pairs = [
|
||||||
|
(sha_brace, sha_text),
|
||||||
|
(message_brace, message_text),
|
||||||
|
(digest_brace, digest_text),
|
||||||
|
]
|
||||||
|
|
||||||
|
self.add(group)
|
||||||
|
for brace, text in brace_text_pairs:
|
||||||
|
self.play(
|
||||||
|
GrowFromCenter(brace),
|
||||||
|
Write(text, run_time = 2)
|
||||||
|
)
|
||||||
|
self.dither()
|
||||||
|
self.dither()
|
||||||
|
for mob in digest, message:
|
||||||
|
self.play(LaggedStart(
|
||||||
|
ApplyMethod, mob,
|
||||||
|
lambda m : (m.highlight, YELLOW),
|
||||||
|
rate_func = there_and_back,
|
||||||
|
run_time = 1
|
||||||
|
))
|
||||||
|
self.dither()
|
||||||
|
|
||||||
|
new_lhs, new_digest = groups[1]
|
||||||
|
char = new_lhs[2][-5]
|
||||||
|
arrow = Arrow(UP, ORIGIN, buff = 0)
|
||||||
|
arrow.next_to(char, UP)
|
||||||
|
arrow.highlight(RED)
|
||||||
|
self.play(ShowCreation(arrow))
|
||||||
|
for new_group in groups[1:]:
|
||||||
|
new_lhs, new_digest = new_group
|
||||||
|
new_message = new_lhs[2]
|
||||||
|
self.play(
|
||||||
|
Transform(lhs, new_lhs),
|
||||||
|
message_brace.stretch_to_fit_width, new_message.get_width(),
|
||||||
|
message_brace.next_to, new_message, DOWN,
|
||||||
|
MaintainPositionRelativeTo(message_text, message_brace),
|
||||||
|
MaintainPositionRelativeTo(sha_brace, lhs[0]),
|
||||||
|
MaintainPositionRelativeTo(sha_text, sha_brace)
|
||||||
|
)
|
||||||
|
self.play(Transform(
|
||||||
|
digest, new_digest,
|
||||||
|
run_time = 2,
|
||||||
|
submobject_mode = "lagged_start",
|
||||||
|
path_arc = np.pi/2
|
||||||
|
))
|
||||||
|
if arrow in self.get_mobjects():
|
||||||
|
self.dither()
|
||||||
|
self.play(FadeOut(arrow))
|
||||||
|
self.dither()
|
||||||
|
|
||||||
|
new_sha_text = TextMobject(
|
||||||
|
"Cryptographic", "hash function"
|
||||||
|
)
|
||||||
|
new_sha_text.next_to(sha_brace, UP)
|
||||||
|
new_sha_text.shift_onto_screen()
|
||||||
|
new_sha_text.highlight(YELLOW)
|
||||||
|
new_sha_text[0].highlight(GREEN)
|
||||||
|
self.play(Transform(sha_text, new_sha_text))
|
||||||
|
self.dither()
|
||||||
|
|
||||||
|
self.lhs = lhs
|
||||||
|
self.message = message
|
||||||
|
self.digest = digest
|
||||||
|
self.digest_text = digest_text
|
||||||
|
self.message_text = message_text
|
||||||
|
|
||||||
|
def inverse_function_question(self):
|
||||||
|
arrow = Arrow(3*RIGHT, 3*LEFT, buff = 0)
|
||||||
|
arrow.set_stroke(width = 8)
|
||||||
|
arrow.highlight(RED)
|
||||||
|
everything = VGroup(*self.get_mobjects())
|
||||||
|
arrow.next_to(everything, DOWN)
|
||||||
|
words = TextMobject("Inverse is infeasible")
|
||||||
|
words.highlight(RED)
|
||||||
|
words.next_to(arrow, DOWN)
|
||||||
|
|
||||||
|
self.play(ShowCreation(arrow))
|
||||||
|
self.play(Write(words))
|
||||||
|
self.dither()
|
||||||
|
|
||||||
|
def issue_challenge(self):
|
||||||
|
desired_output_text = TextMobject("Desired output")
|
||||||
|
desired_output_text.move_to(self.digest_text)
|
||||||
|
desired_output_text.highlight(YELLOW)
|
||||||
|
new_digest = sha256_tex_mob("Challenge")
|
||||||
|
new_digest.replace(self.digest)
|
||||||
|
q_marks = TextMobject("???")
|
||||||
|
q_marks.move_to(self.message_text)
|
||||||
|
q_marks.highlight(BLUE)
|
||||||
|
|
||||||
|
self.play(
|
||||||
|
Transform(
|
||||||
|
self.digest, new_digest,
|
||||||
|
run_time = 2,
|
||||||
|
submobject_mode = "lagged_start",
|
||||||
|
path_arc = np.pi/2
|
||||||
|
),
|
||||||
|
Transform(self.digest_text, desired_output_text)
|
||||||
|
)
|
||||||
|
self.play(
|
||||||
|
FadeOut(self.message),
|
||||||
|
Transform(self.message_text, q_marks)
|
||||||
|
)
|
||||||
|
self.dither()
|
||||||
|
|
||||||
|
def shift_everything_down(self):
|
||||||
|
everything = VGroup(*self.get_top_level_mobjects())
|
||||||
|
self.play(
|
||||||
|
everything.scale, 0.85,
|
||||||
|
everything.to_edge, DOWN
|
||||||
|
)
|
||||||
|
|
||||||
|
def guess_and_check(self):
|
||||||
|
groups = VGroup()
|
||||||
|
for x in range(32):
|
||||||
|
message = "Guess \\#%d"%x
|
||||||
|
lhs = TextMobject(
|
||||||
|
"SHA256(``", message, "'') = ",
|
||||||
|
arg_separator = ""
|
||||||
|
)
|
||||||
|
lhs.highlight_by_tex("Guess", BLUE)
|
||||||
|
digest = sha256_tex_mob(message)
|
||||||
|
digest.next_to(lhs, RIGHT)
|
||||||
|
group = VGroup(lhs, digest)
|
||||||
|
group.scale(0.85)
|
||||||
|
group.next_to(self.digest, UP, aligned_edge = RIGHT)
|
||||||
|
group.to_edge(UP)
|
||||||
|
groups.add(group)
|
||||||
|
|
||||||
|
group = groups[0]
|
||||||
|
self.play(FadeIn(group))
|
||||||
|
for new_group in groups[1:]:
|
||||||
|
self.play(Transform(
|
||||||
|
group[0], new_group[0],
|
||||||
|
run_time = 0.5,
|
||||||
|
))
|
||||||
|
self.play(Transform(
|
||||||
|
group[1], new_group[1],
|
||||||
|
run_time = 1,
|
||||||
|
submobject_mode = "lagged_start"
|
||||||
|
))
|
||||||
|
|
||||||
|
class PonderScematic(Scene):
|
||||||
|
def construct(self):
|
||||||
|
randy = Randolph()
|
||||||
|
randy.to_corner(DOWN+LEFT)
|
||||||
|
self.play(randy.change, "confused", ORIGIN)
|
||||||
|
for x in range(3):
|
||||||
|
self.play(Blink(randy))
|
||||||
|
self.dither(2)
|
||||||
|
|
||||||
|
class ViewingSLLCertificate(ExternallyAnimatedScene):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class SHA256ToProofOfWork(TeacherStudentsScene):
|
||||||
|
def construct(self):
|
||||||
|
sha = TextMobject("SHA256")
|
||||||
|
proof = TextMobject("Proof of work")
|
||||||
|
arrow = Arrow(LEFT, RIGHT)
|
||||||
|
group = VGroup(sha, arrow, proof)
|
||||||
|
group.arrange_submobjects(RIGHT)
|
||||||
|
group.next_to(self.teacher, UP, buff = LARGE_BUFF)
|
||||||
|
group.to_edge(RIGHT, buff = LARGE_BUFF)
|
||||||
|
|
||||||
|
self.play(
|
||||||
|
Write(sha, run_time = 1),
|
||||||
|
self.teacher.change, "raise_right_hand"
|
||||||
|
)
|
||||||
|
self.play(ShowCreation(arrow))
|
||||||
|
self.play(Write(proof, run_time = 1))
|
||||||
|
self.dither(3)
|
||||||
|
|
||||||
|
class IntroduceNonceOnTrasactions(LedgerScene):
|
||||||
|
CONFIG = {
|
||||||
|
"denomination" : "LD",
|
||||||
|
"ledger_width" : 5,
|
||||||
|
"ledger_line_height" : 0.3,
|
||||||
|
}
|
||||||
|
def construct(self):
|
||||||
|
self.add(self.get_ledger())
|
||||||
|
self.hash_with_nonce()
|
||||||
|
self.write_probability()
|
||||||
|
self.guess_and_check()
|
||||||
|
self.name_proof_of_work()
|
||||||
|
self.change_ledger()
|
||||||
|
self.guess_and_check()
|
||||||
|
|
||||||
|
def hash_with_nonce(self):
|
||||||
|
ledger = self.ledger
|
||||||
|
self.add(*[
|
||||||
|
self.add_payment_line_to_ledger(*payment)
|
||||||
|
for payment in [
|
||||||
|
("Alice", "Bob", 20),
|
||||||
|
("Alice", "You", 30),
|
||||||
|
("Charlie", "You", 100),
|
||||||
|
]
|
||||||
|
])
|
||||||
|
|
||||||
|
nonce = TexMobject(str(2**30 + hash("Hey there")%(2**15)))
|
||||||
|
nonce.next_to(ledger, RIGHT, LARGE_BUFF)
|
||||||
|
nonce.highlight(GREEN_C)
|
||||||
|
nonce_brace = Brace(nonce, DOWN)
|
||||||
|
special_word = nonce_brace.get_text("Special number")
|
||||||
|
arrow = Arrow(LEFT, RIGHT, buff = 0)
|
||||||
|
arrow.next_to(ledger, RIGHT)
|
||||||
|
arrow.shift(MED_LARGE_BUFF*DOWN)
|
||||||
|
sha = TextMobject("SHA256")
|
||||||
|
sha.next_to(arrow, UP)
|
||||||
|
digest = sha256_tex_mob(
|
||||||
|
"""Man, you're reading this deeply into
|
||||||
|
the code behind videos? I'm touched,
|
||||||
|
really touched. Keeping loving math, my
|
||||||
|
friend. """,
|
||||||
|
n_forced_start_zeros = 30,
|
||||||
|
)
|
||||||
|
digest.next_to(arrow, RIGHT)
|
||||||
|
zeros = VGroup(*digest[:30])
|
||||||
|
zeros_brace = Brace(zeros, UP)
|
||||||
|
zeros_words = zeros_brace.get_text("30 zeros")
|
||||||
|
|
||||||
|
self.play(LaggedStart(
|
||||||
|
FadeIn, VGroup(special_word, nonce_brace, nonce)
|
||||||
|
))
|
||||||
|
self.dither()
|
||||||
|
self.play(
|
||||||
|
nonce.next_to, ledger.content, DOWN, MED_SMALL_BUFF, LEFT,
|
||||||
|
FadeOut(special_word),
|
||||||
|
FadeOut(nonce_brace)
|
||||||
|
)
|
||||||
|
ledger.content.add(nonce)
|
||||||
|
decomposed_ledger = VGroup(*filter(
|
||||||
|
lambda m : not m.is_subpath,
|
||||||
|
ledger.family_members_with_points()
|
||||||
|
))
|
||||||
|
self.play(
|
||||||
|
ShowCreation(arrow),
|
||||||
|
FadeIn(sha)
|
||||||
|
)
|
||||||
|
self.play(LaggedStart(
|
||||||
|
ApplyMethod, decomposed_ledger,
|
||||||
|
lambda m : (m.highlight, YELLOW),
|
||||||
|
rate_func = there_and_back
|
||||||
|
))
|
||||||
|
point = VectorizedPoint(sha.get_center())
|
||||||
|
point.set_fill(opacity = 1)
|
||||||
|
self.play(LaggedStart(
|
||||||
|
Transform, decomposed_ledger.copy(),
|
||||||
|
lambda m : (m, point),
|
||||||
|
run_time = 1
|
||||||
|
))
|
||||||
|
bit_iter = iter(digest)
|
||||||
|
self.play(LaggedStart(
|
||||||
|
ReplacementTransform,
|
||||||
|
VGroup(*[point.copy() for x in range(256)]),
|
||||||
|
lambda m : (m, bit_iter.next()),
|
||||||
|
))
|
||||||
|
self.remove(*self.get_mobjects_from_last_animation())
|
||||||
|
self.add(digest)
|
||||||
|
self.play(
|
||||||
|
GrowFromCenter(zeros_brace),
|
||||||
|
Write(zeros_words, run_time = 1)
|
||||||
|
)
|
||||||
|
self.play(LaggedStart(
|
||||||
|
ApplyMethod, zeros,
|
||||||
|
lambda m : (m.highlight, YELLOW)
|
||||||
|
))
|
||||||
|
self.dither(2)
|
||||||
|
|
||||||
|
self.nonce = nonce
|
||||||
|
self.digest = digest
|
||||||
|
self.zeros_brace = zeros_brace
|
||||||
|
self.zeros_words = zeros_words
|
||||||
|
|
||||||
|
def write_probability(self):
|
||||||
|
probability = TextMobject(
|
||||||
|
"Probability: $\\frac{1}{2^{30}}$",
|
||||||
|
"$\\approx \\frac{1}{1{,}000{,}000{,}000}$",
|
||||||
|
)
|
||||||
|
probability.next_to(self.zeros_words, UP, MED_LARGE_BUFF)
|
||||||
|
|
||||||
|
self.play(FadeIn(probability[0]))
|
||||||
|
self.dither()
|
||||||
|
self.play(Write(probability[1], run_time = 2))
|
||||||
|
self.dither(2)
|
||||||
|
|
||||||
|
def guess_and_check(self):
|
||||||
|
q_mark = TexMobject("?")
|
||||||
|
q_mark.highlight(RED)
|
||||||
|
q_mark.next_to(self.zeros_words, RIGHT, SMALL_BUFF)
|
||||||
|
|
||||||
|
self.digest.save_state()
|
||||||
|
self.nonce.save_state()
|
||||||
|
|
||||||
|
self.play(FadeIn(q_mark))
|
||||||
|
for x in range(1, 13):
|
||||||
|
nonce = TexMobject(str(x))
|
||||||
|
nonce.move_to(self.nonce)
|
||||||
|
nonce.highlight(GREEN_C)
|
||||||
|
digest = sha256_tex_mob(str(x))
|
||||||
|
digest.replace(self.digest)
|
||||||
|
|
||||||
|
self.play(Transform(
|
||||||
|
self.nonce, nonce,
|
||||||
|
run_time = 1 if x == 1 else 0.3
|
||||||
|
))
|
||||||
|
self.play(Transform(
|
||||||
|
self.digest, digest,
|
||||||
|
run_time = 1,
|
||||||
|
submobject_mode = "lagged_start"
|
||||||
|
))
|
||||||
|
self.dither()
|
||||||
|
self.play(self.nonce.restore)
|
||||||
|
self.play(
|
||||||
|
self.digest.restore,
|
||||||
|
submobject_mode = "lagged_start",
|
||||||
|
run_time = 2
|
||||||
|
)
|
||||||
|
self.play(FadeOut(q_mark))
|
||||||
|
self.dither()
|
||||||
|
|
||||||
|
def name_proof_of_work(self):
|
||||||
|
words = TextMobject("``Proof of work''")
|
||||||
|
words.next_to(self.nonce, DOWN, LARGE_BUFF)
|
||||||
|
words.shift(MED_LARGE_BUFF*RIGHT)
|
||||||
|
words.highlight(GREEN)
|
||||||
|
arrow = Arrow(
|
||||||
|
words.get_top(), self.nonce.get_bottom(),
|
||||||
|
color = WHITE,
|
||||||
|
tip_length = 0.15
|
||||||
|
)
|
||||||
|
self.play(Write(words, run_time = 2))
|
||||||
|
self.play(ShowCreation(arrow))
|
||||||
|
self.dither()
|
||||||
|
|
||||||
|
def change_ledger(self):
|
||||||
|
amount = self.ledger.content[2][-1]
|
||||||
|
new_amount = TextMobject("300 LD")
|
||||||
|
new_amount.scale_to_fit_height(amount.get_height())
|
||||||
|
new_amount.highlight(amount.get_color())
|
||||||
|
new_amount.move_to(amount, LEFT)
|
||||||
|
|
||||||
|
new_digest = sha256_tex_mob("Ah shucks")
|
||||||
|
new_digest.replace(self.digest)
|
||||||
|
|
||||||
|
dot = Dot(amount.get_center())
|
||||||
|
dot.set_fill(opacity = 0.5)
|
||||||
|
|
||||||
|
self.play(FocusOn(amount))
|
||||||
|
self.play(Transform(amount, new_amount))
|
||||||
|
self.play(
|
||||||
|
dot.move_to, new_digest,
|
||||||
|
dot.set_fill, None, 0
|
||||||
|
)
|
||||||
|
self.play(Transform(
|
||||||
|
self.digest, new_digest,
|
||||||
|
submobject_mode = "lagged_start",
|
||||||
|
))
|
||||||
|
|
||||||
|
class ShowSomeBroadcasting(DistributedLedgerScene):
|
||||||
|
def construct(self):
|
||||||
|
self.add_large_network_and_distributed_ledger()
|
||||||
|
lines = self.network.lines.copy()
|
||||||
|
lines.add(*[
|
||||||
|
line.copy().rotate(np.pi)
|
||||||
|
for line in lines
|
||||||
|
])
|
||||||
|
|
||||||
|
point = VectorizedPoint(self.pi_creatures.get_center())
|
||||||
|
last_pi = None
|
||||||
|
for pi in self.pi_creatures:
|
||||||
|
outgoing_lines = []
|
||||||
|
for line in lines:
|
||||||
|
vect = line.get_start() - pi.get_center()
|
||||||
|
dist = np.linalg.norm(vect)
|
||||||
|
if dist < 2:
|
||||||
|
outgoing_lines.append(line)
|
||||||
|
dots = VGroup()
|
||||||
|
for line in outgoing_lines:
|
||||||
|
dot = Dot(line.get_start())
|
||||||
|
dot.highlight(YELLOW)
|
||||||
|
dot.generate_target()
|
||||||
|
dot.target.move_to(line.get_end())
|
||||||
|
for alt_pi in self.pi_creatures:
|
||||||
|
vect = line.get_end() - alt_pi.get_center()
|
||||||
|
dist = np.linalg.norm(vect)
|
||||||
|
if dist < 2:
|
||||||
|
dot.ledger = alt_pi.ledger
|
||||||
|
dots.add(dot)
|
||||||
|
self.play(
|
||||||
|
Animation(point),
|
||||||
|
Broadcast(pi),
|
||||||
|
*[
|
||||||
|
Succession(
|
||||||
|
FadeIn(dot),
|
||||||
|
MoveToTarget(dot, run_time = 2),
|
||||||
|
)
|
||||||
|
for dot in dots
|
||||||
|
]
|
||||||
|
)
|
||||||
|
self.play(*it.chain(*[
|
||||||
|
[dot.move_to, dot.ledger, dot.set_fill, None, 0]
|
||||||
|
for dot in dots
|
||||||
|
]))
|
||||||
|
|
||||||
|
class IntroduceBlockChain(Scene):
|
||||||
|
CONFIG = {
|
||||||
|
"transaction_color" : YELLOW,
|
||||||
|
"proof_of_work_color" : GREEN,
|
||||||
|
"prev_hash_color" : BLUE,
|
||||||
|
"block_width" : 3,
|
||||||
|
"block_height" : 3.5,
|
||||||
|
"n_transaction_lines" : 8,
|
||||||
|
"payment_height_to_block_height" : 0.15,
|
||||||
|
}
|
||||||
|
def setup(self):
|
||||||
|
ls = LedgerScene()
|
||||||
|
self.names = [
|
||||||
|
name.capitalize()
|
||||||
|
for name in ls.get_names()
|
||||||
|
]
|
||||||
|
self.name_colors = [
|
||||||
|
ls.get_color_from_name(name)
|
||||||
|
for name in self.names
|
||||||
|
]
|
||||||
|
|
||||||
|
def construct(self):
|
||||||
|
self.divide_ledger_into_blocks()
|
||||||
|
self.show_proofs_of_work()
|
||||||
|
self.chain_blocks_together()
|
||||||
|
self.mess_with_early_block()
|
||||||
|
self.propogate_hash_change()
|
||||||
|
self.redo_proof_of_work()
|
||||||
|
self.write_block_chain()
|
||||||
|
|
||||||
|
|
||||||
|
def divide_ledger_into_blocks(self):
|
||||||
|
blocks = VGroup(*[
|
||||||
|
self.get_block() for x in range(3)
|
||||||
|
])
|
||||||
|
blocks.arrange_submobjects(RIGHT, buff = 1.5)
|
||||||
|
blocks.to_edge(UP)
|
||||||
|
|
||||||
|
all_payments = VGroup()
|
||||||
|
all_proofs_of_work = VGroup()
|
||||||
|
for block in blocks:
|
||||||
|
block.remove(block.prev_hash)
|
||||||
|
all_payments.add(*block.payments)
|
||||||
|
all_proofs_of_work.add(block.proof_of_work)
|
||||||
|
|
||||||
|
blocks_word = TextMobject("Blocks")
|
||||||
|
blocks_word.scale(1.5)
|
||||||
|
blocks_word.shift(2*DOWN)
|
||||||
|
arrows = VGroup(*[
|
||||||
|
Arrow(
|
||||||
|
blocks_word.get_top(), block.get_bottom(),
|
||||||
|
buff = MED_LARGE_BUFF,
|
||||||
|
color = WHITE
|
||||||
|
)
|
||||||
|
for block in blocks
|
||||||
|
])
|
||||||
|
|
||||||
|
self.play(LaggedStart(FadeIn, blocks))
|
||||||
|
self.play(
|
||||||
|
Write(blocks_word),
|
||||||
|
LaggedStart(
|
||||||
|
ShowCreation, arrows,
|
||||||
|
run_time = 1,
|
||||||
|
lag_factor = 0.6,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
self.dither()
|
||||||
|
for group in all_payments, all_proofs_of_work:
|
||||||
|
self.play(LaggedStart(
|
||||||
|
Indicate, group,
|
||||||
|
rate_func = there_and_back,
|
||||||
|
scale_factor = 1.1,
|
||||||
|
))
|
||||||
|
self.play(*map(FadeOut, [blocks_word, arrows]))
|
||||||
|
|
||||||
|
self.blocks = blocks
|
||||||
|
|
||||||
|
def show_proofs_of_work(self):
|
||||||
|
random.seed(0)
|
||||||
|
blocks = self.blocks
|
||||||
|
|
||||||
|
proofs_of_work = VGroup()
|
||||||
|
new_proofs_of_work = VGroup()
|
||||||
|
digests = VGroup()
|
||||||
|
arrows = VGroup()
|
||||||
|
sha_words = VGroup()
|
||||||
|
signatures = VGroup()
|
||||||
|
|
||||||
|
for block in blocks:
|
||||||
|
proofs_of_work.add(block.proof_of_work)
|
||||||
|
num_str = str(random.randint(0, 10**12))
|
||||||
|
number = TexMobject(num_str)
|
||||||
|
number.highlight(self.proof_of_work_color)
|
||||||
|
number.replace(block.proof_of_work, dim_to_match = 1)
|
||||||
|
new_proofs_of_work.add(number)
|
||||||
|
|
||||||
|
digest = sha256_tex_mob(num_str, 60)
|
||||||
|
digest.scale(0.7)
|
||||||
|
digest.move_to(block).to_edge(DOWN)
|
||||||
|
VGroup(*digest[:60]).highlight(YELLOW)
|
||||||
|
arrow = Arrow(block, digest)
|
||||||
|
sha = TextMobject("SHA256")
|
||||||
|
sha.scale(0.7)
|
||||||
|
point = arrow.get_center()
|
||||||
|
sha.next_to(point, UP, SMALL_BUFF)
|
||||||
|
sha.rotate(-np.pi/2, about_point = point)
|
||||||
|
sha.shift(SMALL_BUFF*UP)
|
||||||
|
digests.add(digest)
|
||||||
|
arrows.add(arrow)
|
||||||
|
sha_words.add(sha)
|
||||||
|
|
||||||
|
for payment in block.payments[:2]:
|
||||||
|
signatures.add(payment[-1])
|
||||||
|
|
||||||
|
proofs_of_work.save_state()
|
||||||
|
|
||||||
|
self.play(Transform(
|
||||||
|
proofs_of_work, new_proofs_of_work,
|
||||||
|
submobject_mode = "lagged_start"
|
||||||
|
))
|
||||||
|
self.play(
|
||||||
|
ShowCreation(arrows),
|
||||||
|
Write(sha_words),
|
||||||
|
run_time = 2
|
||||||
|
)
|
||||||
|
self.play(Write(digests))
|
||||||
|
self.dither()
|
||||||
|
for group in signatures, proofs_of_work:
|
||||||
|
self.play(LaggedStart(
|
||||||
|
Indicate, group,
|
||||||
|
run_time = 2,
|
||||||
|
rate_func = there_and_back,
|
||||||
|
))
|
||||||
|
self.dither()
|
||||||
|
self.play(
|
||||||
|
proofs_of_work.restore,
|
||||||
|
FadeOut(sha_words)
|
||||||
|
)
|
||||||
|
|
||||||
|
self.digests = digests
|
||||||
|
self.sha_arrows = arrows
|
||||||
|
|
||||||
|
def chain_blocks_together(self):
|
||||||
|
blocks = self.blocks
|
||||||
|
digests = self.digests
|
||||||
|
sha_arrows = self.sha_arrows
|
||||||
|
block_spacing = blocks[1].get_center() - blocks[0].get_center()
|
||||||
|
prev_hashes = VGroup(*[
|
||||||
|
block.prev_hash for block in blocks
|
||||||
|
])
|
||||||
|
|
||||||
|
prev_hashes.add(
|
||||||
|
prev_hashes[-1].copy().shift(block_spacing).fade(1)
|
||||||
|
)
|
||||||
|
|
||||||
|
new_arrows = VGroup()
|
||||||
|
for block in blocks:
|
||||||
|
end = np.array([
|
||||||
|
block.get_left()[0] + block_spacing[0],
|
||||||
|
block.prev_hash.get_center()[1],
|
||||||
|
0
|
||||||
|
])
|
||||||
|
arrow = Arrow(end+LEFT, end, buff = SMALL_BUFF)
|
||||||
|
arrow.points[0] = block.get_right()
|
||||||
|
arrow.points[1] = block.get_right() + RIGHT
|
||||||
|
arrow.points[2] = end + LEFT + SMALL_BUFF*UP
|
||||||
|
new_arrows.add(arrow)
|
||||||
|
|
||||||
|
for i in range(3):
|
||||||
|
self.play(
|
||||||
|
ReplacementTransform(digests[i], prev_hashes[i+1]),
|
||||||
|
Transform(sha_arrows[i], new_arrows[i])
|
||||||
|
)
|
||||||
|
arrow = new_arrows[0].copy().shift(-block_spacing)
|
||||||
|
sha_arrows.add_to_back(arrow)
|
||||||
|
self.play(*map(FadeIn, [arrow, prev_hashes[0]]))
|
||||||
|
self.dither(2)
|
||||||
|
|
||||||
|
self.prev_hashes = prev_hashes
|
||||||
|
|
||||||
|
def mess_with_early_block(self):
|
||||||
|
blocks = self.blocks
|
||||||
|
amount = blocks[0].payments[1][3]
|
||||||
|
new_amount = TextMobject("400 LD")
|
||||||
|
new_amount.scale_to_fit_height(amount.get_height())
|
||||||
|
new_amount.highlight(RED)
|
||||||
|
new_amount.move_to(amount, LEFT)
|
||||||
|
|
||||||
|
self.play(FocusOn(amount))
|
||||||
|
self.play(Transform(amount, new_amount))
|
||||||
|
self.dither()
|
||||||
|
self.play(Swap(*blocks[:2]))
|
||||||
|
self.dither()
|
||||||
|
|
||||||
|
blocks.submobjects[:2] = blocks.submobjects[1::-1]
|
||||||
|
|
||||||
|
def propogate_hash_change(self):
|
||||||
|
alt_prev_hashes = self.prev_hashes.copy()
|
||||||
|
alt_prev_hashes.highlight(RED)
|
||||||
|
|
||||||
|
for block, prev_hash in zip(self.blocks, alt_prev_hashes[1:]):
|
||||||
|
rect = block.rect.copy()
|
||||||
|
rect.set_stroke(RED, 8)
|
||||||
|
self.play(ShowCreation(rect))
|
||||||
|
self.play(ReplacementTransform(rect, prev_hash))
|
||||||
|
self.alt_prev_hashes = alt_prev_hashes
|
||||||
|
|
||||||
|
def redo_proof_of_work(self):
|
||||||
|
proofs_of_work = VGroup(*[
|
||||||
|
block.proof_of_work for block in self.blocks
|
||||||
|
])
|
||||||
|
hashes = self.alt_prev_hashes[1:]
|
||||||
|
|
||||||
|
self.play(FadeOut(proofs_of_work))
|
||||||
|
for proof_of_work, prev_hash in zip(proofs_of_work, hashes):
|
||||||
|
num_pow_group = VGroup(*[
|
||||||
|
Integer(random.randint(10**9, 10**10))
|
||||||
|
for x in range(50)
|
||||||
|
])
|
||||||
|
num_pow_group.highlight(proof_of_work.get_color())
|
||||||
|
num_pow_group.scale_to_fit_width(proof_of_work.get_width())
|
||||||
|
num_pow_group.move_to(proof_of_work)
|
||||||
|
for num_pow in num_pow_group:
|
||||||
|
self.add(num_pow)
|
||||||
|
self.dither(1./20)
|
||||||
|
self.remove(num_pow)
|
||||||
|
self.add(num_pow)
|
||||||
|
prev_hash.highlight(BLUE)
|
||||||
|
|
||||||
|
def write_block_chain(self):
|
||||||
|
ledger = TextMobject("Ledger")
|
||||||
|
ledger.next_to(self.blocks, DOWN)
|
||||||
|
cross = Cross(ledger)
|
||||||
|
block_chain = TextMobject("``Block Chain''")
|
||||||
|
block_chain.next_to(ledger, DOWN)
|
||||||
|
|
||||||
|
self.play(FadeIn(ledger))
|
||||||
|
self.play(
|
||||||
|
ShowCreation(cross),
|
||||||
|
Write(block_chain)
|
||||||
|
)
|
||||||
|
self.dither(2)
|
||||||
|
|
||||||
|
|
||||||
|
######
|
||||||
|
|
||||||
|
def get_block(self):
|
||||||
|
block = VGroup()
|
||||||
|
rect = Rectangle(
|
||||||
|
color = WHITE,
|
||||||
|
height = self.block_height,
|
||||||
|
width = self.block_width,
|
||||||
|
)
|
||||||
|
h_line1, h_line2 = [
|
||||||
|
Line(
|
||||||
|
rect.get_left(), rect.get_right()
|
||||||
|
).shift(0.3*rect.get_height()*vect)
|
||||||
|
for vect in UP, DOWN
|
||||||
|
]
|
||||||
|
|
||||||
|
payments = VGroup()
|
||||||
|
if not hasattr(self, "transaction_counter"):
|
||||||
|
self.transaction_counter = 0
|
||||||
|
for x in range(2):
|
||||||
|
hashes = [
|
||||||
|
hash("%d %d"%(seed, self.transaction_counter))
|
||||||
|
for seed in range(3)
|
||||||
|
]
|
||||||
|
payment = TextMobject(
|
||||||
|
self.names[hashes[0]%3],
|
||||||
|
"pays",
|
||||||
|
self.names[hashes[1]%4],
|
||||||
|
"%d0 LD"%(hashes[2]%9 + 1),
|
||||||
|
)
|
||||||
|
payment.highlight_by_tex("LD", YELLOW)
|
||||||
|
for name, color in zip(self.names, self.name_colors):
|
||||||
|
payment.highlight_by_tex(name, color)
|
||||||
|
signature = TextMobject("$\\langle$ Signature $\\rangle$")
|
||||||
|
signature.highlight(payment[0].get_color())
|
||||||
|
signature.next_to(payment, DOWN, SMALL_BUFF)
|
||||||
|
payment.add(signature)
|
||||||
|
|
||||||
|
factor = self.payment_height_to_block_height
|
||||||
|
payment.scale_to_fit_height(factor*rect.get_height())
|
||||||
|
payments.add(payment)
|
||||||
|
self.transaction_counter += 1
|
||||||
|
payments.add(TexMobject("\\dots").scale(0.5))
|
||||||
|
payments.arrange_submobjects(DOWN, buff = MED_SMALL_BUFF)
|
||||||
|
payments.next_to(h_line1, DOWN)
|
||||||
|
|
||||||
|
proof_of_work = TextMobject("Proof of work")
|
||||||
|
proof_of_work.highlight(self.proof_of_work_color)
|
||||||
|
proof_of_work.scale(0.8)
|
||||||
|
proof_of_work.move_to(
|
||||||
|
VGroup(h_line2, VectorizedPoint(rect.get_bottom()))
|
||||||
|
)
|
||||||
|
|
||||||
|
prev_hash = TextMobject("Prev hash")
|
||||||
|
prev_hash.scale(0.8)
|
||||||
|
prev_hash.highlight(self.prev_hash_color)
|
||||||
|
prev_hash.move_to(
|
||||||
|
VGroup(h_line1, VectorizedPoint(rect.get_top()))
|
||||||
|
)
|
||||||
|
|
||||||
|
block.rect = rect
|
||||||
|
block.h_lines = VGroup(h_line1, h_line2)
|
||||||
|
block.payments = payments
|
||||||
|
block.proof_of_work = proof_of_work
|
||||||
|
block.prev_hash = prev_hash
|
||||||
|
block.digest_mobject_attrs()
|
||||||
|
return block
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -14,6 +14,8 @@
|
|||||||
\begin{document}
|
\begin{document}
|
||||||
\centering
|
\centering
|
||||||
|
|
||||||
$\displaystyle YourTextHere$
|
\begin{align*}
|
||||||
|
YourTextHere
|
||||||
|
\end{align*}
|
||||||
|
|
||||||
\end{document}
|
\end{document}
|
@ -563,7 +563,7 @@ class PiCreatureScene(Scene):
|
|||||||
return self
|
return self
|
||||||
|
|
||||||
def dither(self, time = 1, blink = True):
|
def dither(self, time = 1, blink = True):
|
||||||
while time > 0:
|
while time >= 1:
|
||||||
time_to_blink = self.total_dither_time%self.seconds_to_blink == 0
|
time_to_blink = self.total_dither_time%self.seconds_to_blink == 0
|
||||||
if blink and self.any_pi_creatures_on_screen() and time_to_blink:
|
if blink and self.any_pi_creatures_on_screen() and time_to_blink:
|
||||||
self.blink()
|
self.blink()
|
||||||
@ -571,6 +571,8 @@ class PiCreatureScene(Scene):
|
|||||||
Scene.dither(self)
|
Scene.dither(self)
|
||||||
time -= 1
|
time -= 1
|
||||||
self.total_dither_time += 1
|
self.total_dither_time += 1
|
||||||
|
if time > 0:
|
||||||
|
Scene.dither(self, time)
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def change_mode(self, mode):
|
def change_mode(self, mode):
|
||||||
|
@ -265,22 +265,6 @@ class DoubleArrow(Arrow):
|
|||||||
Arrow.__init__(self, *args, **kwargs)
|
Arrow.__init__(self, *args, **kwargs)
|
||||||
self.add_tip(add_at_end = False)
|
self.add_tip(add_at_end = False)
|
||||||
|
|
||||||
|
|
||||||
class Cross(VMobject):
|
|
||||||
CONFIG = {
|
|
||||||
"color" : YELLOW,
|
|
||||||
"radius" : 0.3
|
|
||||||
}
|
|
||||||
def generate_points(self):
|
|
||||||
p1, p2, p3, p4 = self.radius * np.array([
|
|
||||||
UP+LEFT,
|
|
||||||
DOWN+RIGHT,
|
|
||||||
UP+RIGHT,
|
|
||||||
DOWN+LEFT,
|
|
||||||
])
|
|
||||||
self.add(Line(p1, p2), Line(p3, p4))
|
|
||||||
self.init_colors()
|
|
||||||
|
|
||||||
class CubicBezier(VMobject):
|
class CubicBezier(VMobject):
|
||||||
def __init__(self, points, **kwargs):
|
def __init__(self, points, **kwargs):
|
||||||
VMobject.__init__(self, **kwargs)
|
VMobject.__init__(self, **kwargs)
|
||||||
|
@ -12,6 +12,13 @@ from topics.geometry import Circle, Line, Rectangle, Square, \
|
|||||||
Arc, Polygon, SurroundingRectangle
|
Arc, Polygon, SurroundingRectangle
|
||||||
from topics.three_dimensions import Cube
|
from topics.three_dimensions import Cube
|
||||||
|
|
||||||
|
class Lightbulb(SVGMobject):
|
||||||
|
CONFIG = {
|
||||||
|
"file_name" : "lightbulb",
|
||||||
|
"height" : 1,
|
||||||
|
"stroke_color" : YELLOW,
|
||||||
|
}
|
||||||
|
|
||||||
class BitcoinLogo(SVGMobject):
|
class BitcoinLogo(SVGMobject):
|
||||||
CONFIG = {
|
CONFIG = {
|
||||||
"file_name" : "Bitcoin_logo",
|
"file_name" : "Bitcoin_logo",
|
||||||
|
Reference in New Issue
Block a user