Log in

View Full Version : restore "B" clip from "A" clip using a difference clip?


spoRv
17th February 2019, 15:21
I guess if there is a way to restore a, let's call "B" clip, having only an "A" clip and a difference clip between "A" and "B"...

Let me explain better: "A" is any given clip; "B" is the "A" clip, but denoised/degrained/color corrected etc.

Now, I want to get only a difference clip (let's call "DIFF") between the two; then, given only "A" and "DIFF", get "B" back, bit-for-bit identical.

Is it possible?

(please forgive me in advance if it's a silly question, or discussed before, but I've not found anything about this)

:thanks:

DJATOM
17th February 2019, 15:30
The difference part is easy, in avs it can be done with masktools2: mt_makediff(a, b, 3, 3, 3)
Applying that difference is also easy, but probably pointless: mt_adddiff(a, diff, 3, 3, 3) - you will have exact "b" clip.

spoRv
17th February 2019, 16:06
Thanks for the input, DJATOM!

sadly, mt_adddiff(a, diff, 3, 3, 3) doesn't work...
but mt_makediff(a, diff, 3, 3, 3) does! Great!

DJATOM
17th February 2019, 17:03
Ah, indeed. As adddiff adding the difference, it will work like multiplying the incoming difference in the clip A. So yeah, another makediff call will for for your case as it's basically subtracting the diff.

spoRv
17th February 2019, 17:23
This does not work using, for example, "A" letterbox, and "B" like "A" but open matte, or "A" and "B" completely different clips...

spoRv
18th February 2019, 21:12
Is there some genius that could solve the problem of "A" and "B" completely different clips?

I'm pretty sure it could be done, yet I have no idea how...

wonkey_monkey
18th February 2019, 22:34
What is your ultimate aim here? Some kind of obfuscation of clips you already have? Or are you trying to restore a clip that has already had this thing done to it?

mt_makediff, as far as I can tell, will not work properly if the difference between two pixel values is >127 or <-128, which is likely to happen when you have completely different clips. You need something that'll give X = (A-B) modulo 256. Then B = (A-X) modulo 256. (I think that's right but don't take it as definite).

spoRv
18th February 2019, 22:46
Aim is, I want to give someone a "B" clip, ONLY if he/she has the "A" clip - with it, he/she can restore "B" with only "A" and the "DIFF"; without "A", "DIFF" clip would be useless.

Yep, I noted that mt_makediff does not work properly IF the clips are different, or also not perfectly aligned - but seems to work well (at least, according to few tests I made) with denoised/cleaned/regraded versions.

StainlessS
19th February 2019, 00:13
but don't take it as definite
Sounds about right to me.

SpoRv, What you could do is XOR one clip with another, could even use a single frame to XOR the whole clip, and use same single frame clip to both 'Encode' and 'Decode'.
I think MaskTools should have XOR capability. [Sometimes called EOR]

As a daft example, could use eg

RandomSource(Length=Len,Width=W,Height=H,Seed=SECRET_KEY).ConvertToYV12(Matrix=PC601) # to match target clip. EDIT: ADDED MATRIX arg to make better (full range) key clip

as your 'key' encode/decode clip.

Apply XOR, using the key clip, and decode using equivalent key clip at the other end.
All you need pass is the encoded clip, and the SECRET_KEY to create the 'key' clip.
(You could also just use any clip that you both have as a key clip, maybe with fixed seed AddGrain)

EDIT:
If A XOR B = C : Then C XOR B = A [EDIT: Also, C XOR A = B]

EDIT: I believe that above is how RAID 5 works, the third drive (DRIVE_C) holds result of DRIVE A XOR DRIVE_B,
if either drive A or Drive B fails, it can be recovered [EDIT: to a new drive] by XORing the remaining drive with DRIVE_C.

StainlessS
19th February 2019, 01:29
This kinda works, but does not do a particularly good job on ColorBars (due to the content of colorbars probably, works well on live video)


#Colorbars().ConvertToYV12(Matrix="PC601").KillAudio # Clip to Encode (Dont work so well with colorbars)
AviSource("D:\Parade.avi") # Clip to Encode
TARGET=Last

SECRET_KEY = 123456789

FC=FrameCount
W=Width
H=Height
KEY=RandomSource(Length=FC,Width=W,Height=H,Seed=SECRET_KEY).ConvertToYV12(Matrix="PC601")

TARGET.MT_Logic(KEY,"xor",y=3,u=3,v=3) # Encode for sending
ENCODED=Last
Return Encoded

ENCODED.MT_Logic(KEY,"xor",y=3,u=3,v=3) # Decode Encoded
Subtitle("Encoded/Decoded",Align=5)
Return Last


Might also be a good idea to ensure that clip is PC range before encode, and can restore to TV Levels afterwards, the encode would be better,
having ranges not used (ie 0 -> 16, and 236 -> 255) would perhaps result in less than perfect encode.

Encoded: (frame 1000 from JohnMeyer Parade clip). Is much harder to read the billboard on the back of the car.
https://i.postimg.cc/Q9cbPqtZ/ENCODED.jpg (https://postimg.cc/Q9cbPqtZ)

Decoded:
https://i.postimg.cc/ppr0Vzcz/DECODED.jpg (https://postimg.cc/ppr0Vzcz)

EDIT: Maybe you need play with it a bit and try with/without PC range for Key and target clip.

EDIT: Colorbars encoded (you can see some of the bars, sort of. Problem is solid blocks of constant color in src clip)
https://i.postimg.cc/ygWP6zvB/Color-Bars-ENC.jpg (https://postimg.cc/ygWP6zvB)

EDIT: Of course, you could not compress result of encode (although I'm kinda curious what it might look like if you do).

spoRv
19th February 2019, 04:02
So, I set "B" as target, and replaced the key with "A"; then, to get "B" all I need is "A" and obviously the encoded clip; that's brilliant!

I briefly tested it, and, so far, seems perfect.

StainlessS, you are a genius, I knew it, and everybody knews it!

THANKS!!!

Edit: to "shuffle" the encoded clip further, I added invert and turn180; but it's still recognizable, though... isn't there a way to "encrypt" it more, with simple function, that could of course let it back 100% the same? (I know I'm a pain in the... neck! ;) )

spoRv
19th February 2019, 05:00
I've made two simple function to shuffle video... they are quite basic, but do the job; indeed, I'd prefer something more "dramatic"! :D

function deconstruct(clip clip) {
w=clip.width/4
h=clip.height/4
clip
a01=crop(0 ,0 ,w,h).fliphorizontal
a02=crop(w ,0 ,w,h).turn180
a03=crop(w*2,0 ,w,h).fliphorizontal
a04=crop(w*3,0 ,0,h).invert("br")
a05=crop(0 ,h ,w,h).invert
a06=crop(w ,h ,w,h).flipvertical
a07=crop(w*2,h ,w,h).swapuv
a08=crop(w*3,h ,0,h).turn180
a09=crop(0 ,h*2,w,h).swapuv
a10=crop(w ,h*2,w,h).invert("rg")
a11=crop(w*2,h*2,w,h).turn180
a12=crop(w*3,h*2,0,h).invert
a13=crop(0 ,h*3,w,0).swapuv
a14=crop(w ,h*3,w,0).flipvertical
a15=crop(w*2,h*3,w,0).invert("gb")
a16=crop(w*3,h*3,0,0).invert

stackvertical(\
stackhorizontal(a12,a05,a08,a15),\
stackhorizontal(a06,a10,a01,a09),\
stackhorizontal(a11,a16,a14,a04),\
stackhorizontal(a03,a07,a13,a02))\
.Invert("BG").turn180.SwapUV
}

function reconstruct(clip clip) {
w=clip.width/4
h=clip.height/4
clip.SwapUV.turn180.Invert("GB")
a12=crop(0 ,0 ,w,h).invert
a05=crop(w ,0 ,w,h).invert
a08=crop(w*2,0 ,w,h).turn180
a15=crop(w*3,0 ,0,h).invert("bg")
a06=crop(0 ,h ,w,h).flipvertical
a10=crop(w ,h ,w,h).invert("gr")
a01=crop(w*2,h ,w,h).fliphorizontal
a09=crop(w*3,h ,0,h).swapuv
a11=crop(0 ,h*2,w,h).turn180
a16=crop(w ,h*2,w,h).invert
a14=crop(w*2,h*2,w,h).flipvertical
a04=crop(w*3,h*2,0,h).invert("rb")
a03=crop(0 ,h*3,w,0).fliphorizontal
a07=crop(w ,h*3,w,0).swapuv
a13=crop(w*2,h*3,w,0).swapuv
a02=crop(w*3,h*3,0,0).turn180

stackvertical(\
stackhorizontal(a01,a02,a03,a04),\
stackhorizontal(a05,a06,a07,a08),\
stackhorizontal(a09,a10,a11,a12),\
stackhorizontal(a13,a14,a15,a16))
}

Frank62
19th February 2019, 11:59
For further "encryption" I'd quick suggest:

separatefields()
a=selectevery(2,0)
b=selectevery(2,1)
a=turn180(a)
interleave(a,b)
weave()

and the other way round to restore. :)

Maybe repeat this procedure with turnleft at the beginning and turnright at the end.

spoRv
19th February 2019, 14:39
Thanks for the idea, Frank62!

New versions:

function deconstruct(clip clip) {
w=clip.width/4
h=clip.height/4
clip

separatefields
a=selectevery(2,0)
b=selectevery(2,1)
a=turn180(a).swapuv
interleave(a,b)
weave

a01=crop(0 ,0 ,w,h).fliphorizontal
a02=crop(w ,0 ,w,h).invert("br")
a03=crop(w*2,0 ,w,h).invert
a04=crop(w*3,0 ,0,h).turn180
a05=crop(0 ,h ,w,h).invert
a06=crop(w ,h ,w,h).flipvertical
a07=crop(w*2,h ,w,h).invert
a08=crop(w*3,h ,0,h).invert("rg")
a09=crop(0 ,h*2,w,h).swapuv
a10=crop(w ,h*2,w,h).turn180
a11=crop(w*2,h*2,w,h).swapuv
a12=crop(w*3,h*2,0,h).turn180
a13=crop(0 ,h*3,w,0).swapuv
a14=crop(w ,h*3,w,0).invert("gb")
a15=crop(w*2,h*3,w,0).flipvertical
a16=crop(w*3,h*3,0,0).fliphorizontal

stackvertical(\
stackhorizontal(a12,a05,a08,a15),\
stackhorizontal(a06,a10,a01,a09),\
stackhorizontal(a11,a16,a14,a04),\
stackhorizontal(a03,a13,a07,a02))

Invert("BG").turn180.SwapUV
separatefields
a=selectevery(2,0)
b=selectevery(2,1)
a=turn180(a).invert
interleave(a,b)
weave
}

function reconstruct(clip clip) {
w=clip.width/4
h=clip.height/4
clip

separatefields
a=selectevery(2,0)
b=selectevery(2,1)
a=turn180(a).invert
interleave(a,b)
weave
SwapUV.turn180.Invert("GB")

a12=crop(0 ,0 ,w,h).turn180
a05=crop(w ,0 ,w,h).invert
a08=crop(w*2,0 ,w,h).invert("gr")
a15=crop(w*3,0 ,0,h).flipvertical
a06=crop(0 ,h ,w,h).flipvertical
a10=crop(w ,h ,w,h).turn180
a01=crop(w*2,h ,w,h).fliphorizontal
a09=crop(w*3,h ,0,h).swapuv
a11=crop(0 ,h*2,w,h).swapuv
a16=crop(w ,h*2,w,h).fliphorizontal
a14=crop(w*2,h*2,w,h).invert("bg")
a04=crop(w*3,h*2,0,h).turn180
a03=crop(0 ,h*3,w,0).invert
a13=crop(w ,h*3,w,0).swapuv
a07=crop(w*2,h*3,w,0).invert
a02=crop(w*3,h*3,0,0).invert("rb")

stackvertical(\
stackhorizontal(a01,a02,a03,a04),\
stackhorizontal(a05,a06,a07,a08),\
stackhorizontal(a09,a10,a11,a12),\
stackhorizontal(a13,a14,a15,a16))

separatefields
a=selectevery(2,0)
b=selectevery(2,1)
a=turn180(a).swapuv
interleave(a,b)
weave
}

It is quite shuffled now!

StainlessS
19th February 2019, 15:03
I also added edit here:

If A XOR B = C : Then C XOR B = A [EDIT: Also, C XOR A = B]


also note this
(You could also just use any clip that you both have as a key clip, maybe with pre arranged fixed seed AddGrain)

You could have a shared secret clip, of same size colorspace as you are sending [sent once only, could be something completely innocuous looking like tv adverts].


Make your SHARED_KEY clip same characteristics as TARGET clip (looping and trim to make same length as TARGET).
Randomize your SHARED_KEY by using eg AddGrain (with some SECRET_KEY as seed),
OR mix together somehow with a RandomSource KEY (using you SECRET_KEY seed). [Overlay with Pre_Shared Opacity arg , or whatever you like].

So long as recipient uses same method to construct the final KEY clip, then you are in business.

Added this to earlier post.
EDIT: Of course, you could not compress result of encode (although I'm kinda curious what it might look like if you do).

StainlessS
19th February 2019, 17:19
OK, time for a bit of reality.

Script used for PC601 encrypt and compress to MEGUI x264 8bit YV12 @ CRF 18, Preset=Medium [EDIT: Input clip is rec601]

SECRET_KEY = 123456789
MATRIX = "PC601"

AviSource("D:\Parade.avi") # Clip to Encode
TARGET=Last

FC=FrameCount
W=Width
H=Height
KEY=RandomSource(Length=FC,Width=W,Height=H,Seed=SECRET_KEY).ConvertToYV12(Matrix=MATRIX)

TARGET.MT_Logic(KEY,"xor",y=3,u=3,v=3) # Encode for sending
ENCODED=Last
Return Encoded

ENCODED.MT_Logic(KEY,"xor",y=3,u=3,v=3) # Decode Encoded
Return Last


Decode after converting back to AVI via ffmpeg [EDIT: Ut_Video rec601]

SECRET_KEY = 123456789
MATRIX = "PC601"

AviSource("D:\ENCDEC_PC601.mp4.AVI") # Clip to Decode
ENCODED=Last

FC=FrameCount
W=Width
H=Height
KEY=RandomSource(Length=FC,Width=W,Height=H,Seed=SECRET_KEY).ConvertToYV12(Matrix=MATRIX)

ENCODED.MT_Logic(KEY,"xor",y=3,u=3,v=3) # Decode Encoded

#Trim(1000,-1)

Return Last

https://i.postimg.cc/SXM39LNY/DEC-PC601.jpg (https://postimg.cc/SXM39LNY)

Script used for Rec601 encrypt and compress to MEGUI x264 8bit YV12 @ CRF 18, Preset=Medium

SECRET_KEY = 123456789
MATRIX = "rec601"

AviSource("D:\Parade.avi") # Clip to Encode
TARGET=Last

FC=FrameCount
W=Width
H=Height
KEY=RandomSource(Length=FC,Width=W,Height=H,Seed=SECRET_KEY).ConvertToYV12(Matrix=MATRIX)

TARGET.MT_Logic(KEY,"xor",y=3,u=3,v=3) # Encode for sending
ENCODED=Last
Return Encoded

ENCODED.MT_Logic(KEY,"xor",y=3,u=3,v=3) # Decode Encoded
Return Last


Decode after converting back to AVI via ffmpeg

SECRET_KEY = 123456789
MATRIX = "rec601"

AviSource("D:\ENCDEC_Rec601.mp4.AVI") # Clip to Decode
ENCODED=Last

FC=FrameCount
W=Width
H=Height
KEY=RandomSource(Length=FC,Width=W,Height=H,Seed=SECRET_KEY).ConvertToYV12(Matrix=MATRIX)

ENCODED.MT_Logic(KEY,"xor",y=3,u=3,v=3) # Decode Encoded

Trim(1000,-1)

Return Last

https://i.postimg.cc/2qRTPsr3/DEC-Rec601.jpg (https://postimg.cc/2qRTPsr3)

Original
https://i.postimg.cc/qNnxX1yr/Frame1000.jpg (https://postimg.cc/qNnxX1yr)

All may not be lost.
I think that if we can convert encrypted 8 bit clip into 10 bit (with a shift so that bit 0 of encrypted is shifted to bit 1 of 10 bit clip, and both bits 0 and bit 9 of 10 bit clip now 0), and then encode
the 10 bit clip, we may get a better result. However, I have no idea how to convert to 10 bit by only shifting by 1 bit.
(I also have no idea how to do a straight forward convert to 10 bit, so some assistance required here).
EDIT: Reverse procedure restoring back to 8 bit before decrypt would also be necessary.

Also, not sure if you can encode YV24 in MeGUI, I tried but it was converted to YV12 even though I told it not to convert when prompted.

EDIT: Have posted request for assistance here:- https://forum.doom9.org/showthread.php?p=1866148#post1866148

Want to test encrypt with 10 bit key after conversion of target clip to 10 bit, AND ALSO
with 8 bit encrypt key before conversion of encrypted clip to 10 bit.

spoRv
19th February 2019, 20:56
Surely compression would play an important role in the encode/decode path; I need to do some tests, but I'll be out for a week, so those should wait.

The idea of shifting the bit is very nice - how to achieve it, is another story... ;)

Meanwhile, I think it will be nice to add two functions, encrypt and decrypt, using only a "key" to decrypt "B", or both a "key" and the "A" clip.

I thought to improve my previous functions, dividing the image in 64 block (8x8) and shuffle and "scramble" them; this should lead to a less recognizable original clip.
For the key, something like 196 characters (64 triplets), where the first two are the blocks (00-63) and the third is the "scrambled" way (something like H = fliphorizontal, V = flipvertical, I = invert etc.)

So, the function should be something like:

clip.enkript("45V32H58I...")

where original block 1 would be moved to position 45 and flipped vertically, 2 to position 32 and flipped horizontally, 3 to position 58 and inverted etc.

Dunno how to extract each triplets...

(note: enKript with the K because I don't know if there are "encript" and "decript" functions around)

I'm a bit lost about this:
If A XOR B = C : Then C XOR B = A [EDIT: Also, C XOR A = B]

OK, time to put things in the luggage, see you all in a week (if the plane will land safe and sound...)! :D

wonkey_monkey
19th February 2019, 22:38
Lossy compression will not be kind to the noisy data you'll be trying to transmit. Is there a reason you can't just send an encrypted zip file containing the whole video file?

spoRv
19th February 2019, 23:22
I know that could be more difficult to recover data using lossy instead of lossless, but I guess that, using high enough bit rate could lead to a good result. Sure, more tests are needed.

Reason? Ethical, more than others. Let's say that I have made a fan edit, and I want to share it only with people that got the original source; this encode will be a step forward it - even if I know that it's always possible to get the source in a "different" way, but at least this is better than nothing, like leaving the fan edit to be downloaded by anyone who says "I have the original source!" :D
I can also add something in the offline world, like take a pic of the original disk and cover, with a paper on top with the person name written on it, for example; best would be to check the actual disk inside the disk player - that will say "hey, this IS the original disk!" - but I'm not aware of any software that would do that, reading a disk, checking if it's IT, and then decode the encoded file...

StainlessS
19th February 2019, 23:30
I'm a bit lost about this:
If A XOR B = C : Then C XOR B = A [EDIT: Also, C XOR A = B]

Basically, where A XOR B = C, you are mixing A and B with result C, this is reversable so that you can with any two [EDIT: and in any order], recover the 3rd using XOR again.


BlankClip(width=480,Height=80)

A = 12345678
B = 987654
C = BitXOR(A,B)

A2 = BitXOR(B,C)
B2 = BitXOR(A,C)

A3 = BitXOR(C,B)
B3 = BitXOR(C,A)

S1=RT_String("A = %d B = %d C = %d",A,B,C)
S2=RT_String("A2 = %d B2 = %d",A2,B2)
S3=RT_String("A3 = %d B3 = %d",A3,B3)

S=S1 + "\n" + S2 + "\n" + S3

Subtitle(S,lsp=0,Font="Courier New")


https://i.postimg.cc/k5DcBSyJ/Example.jpg (https://postimages.org/)


Truth Table XOR (where A and B differ 1 : where same 0) [for each individual bit]
A | B | Result |
_____|_______|________|
0 | 0 | 0 |
0 | 1 | 1 |
1 | 0 | 1 |
1 | 1 | 0 |
_____|_______|________|

XOR, EXCLUSIVE OR.
If Exclusively A, OR Exclusively B, then true, else false

Considering single bits, if A is some single bit number[0,1], we can toggle that bit using XOR where single bit B is 1, but not change if B is 0.

Truth Table XOR (where A and B differ 1 : where same 0) [for each individual bit]
A | B |C=Result|
_____|_______|________|
0 | 0 | 0 | # B=0, no toggle, so Result C is still 0 same as A
0 | 1 | 1 | # B=1, toggle, so Result C now 1, opposite of A
1 | 0 | 1 | # B=0, no toggle, so Result C is still 1 same as A
1 | 1 | 0 | # B=1, toggle, so Result C now 0, opposite of A
_____|_______|________|

If you now XOR whatever Result C, with the same B, it toggles that bit back to what is was in A, ie is reversable using the same XOR value.
So, with eg 32 bit ints A XOR B, wherever there is a 1 in binary B, that same position in binary A is toggled, 0->1, 1->0, do it again and they are toggle back to how they were.
So eg $AAAAAAAA XOR $FFFFFFFF = $55555555, and $55555555 XOR $FFFFFFFF = $AAAAAAAA. [XOR with $FFFFFFFF toggles every bit, XOR with $00000000 no change]
[ Hex $A = binary 1010 : Hex $5 = binary 0101 ]

Where each pixel of a PC.Levels Y8 plane is XOR'ed with $FF, will change $00->$FF and $FF->$00, and produce a photo negative invert. [$00->$FF, $01->$FE, $02->$FD ... $7F->$80, $80->$7F, etc]


XOR is used in bit addition (very very low level in chip), to generate single bit result of adding two bits (excluding carry into next column).
Eg, 1+1=0 with a carry of 1 into the next most significant bit. [1 XOR 1 = 0]

AND gate, used to generate the carry flag into next column.
eg where 1+1, carry = 1 AND 1 = 1

1+1 = 0 carry 1.

| Result | Carry |
A | B | XOR | AND |
_____|_______|________|________|
0 | 0 | 0 | 0 |
0 | 1 | 1 | 0 |
1 | 0 | 1 | 0 |
1 | 1 | 0 | 1 | <<<<<<<<<<
_____|_______|________|________|
XOR Produces result of bit addition, AND produces carry over into next column.
When you already have a carry from a previous column, it gets somewhat more complicated [ADC, Add With Carry, ie add 3 bits at once]

StainlessS
20th February 2019, 00:51
Lossy compression will not be kind to the noisy data you'll be trying to transmit. Is there a reason you can't just send an encrypted zip file containing the whole video file?

We are (me is) currently in experimental stage, perhaps we could do some denoising on random key clip before encrypting/decryption (DCTFilter I think is intended for something like that),
also probably need use of Limiter() plug at some point (on both key and Target clip).
Maybe I got it wrong on needing single bit shift, I'm not sure but suspect that may require a Left shift of 7, rather than a left shift of 1 (so that most significant bit of 8 bit clip is in bit 14,
with bit 15=0. Might also need random bits set in 15 and bit 6, to encourage x264 to think it is detail and not to screw with it.


I'm kinda interested to see if we can get this working, although zip with password would be a helluva lot easier.

EDIT: Currently, have tried encrypt/encode from original JohnMeyer Parade mp4 (~22.5MB) to 10 bit x264 CRF 18 Preset=Slower, and result
was a whopping 980MB, so a wee bit bigger than original source. This was kinda expected, we will be wanting to experiment with some kind
of multi blurring on the random key, will still obfuscate encrypted clip nicely, but with (hopefully) better compression.
Might even try pixelating the random clip, with additional blurring, lots to try out.
We are gonna hav'ta 'suck-it-and-see' what happens.

spoRv
27th February 2019, 20:44
Tried using a compressed version for the difference clip (h264 and h265), and result is not good... hence, the only way to go is lossless, even if it means A HUGE file! :(

StainlessS
3rd March 2019, 15:36
Tried using a compressed version for the difference clip (h264 and h265), and result is not good

Yeh not good, think maybe some of problem down to illegal TV range colors being created via the XOR-ing, [eg fully saturated chroma when BLACK] below demos it
(I modded the KEY clip genny to be a bit smoother, still no joy at all).


Function EncryptPrep(clip c) { Return c.ConvertToYV12.Limiter(min_luma=16, max_luma=235, min_chroma=16, max_chroma=240 ) }

Function GenRandomKey(clip c,int Seed,Int "Rad",int "Y_Lim",Int "UV_Lim") {
Rad=Default(Rad,4) Y_Lim=Default(Y_Lim,20) UV_Lim=Default(UV_Lim,20)
W=round(c.Width/(Rad*4))*4 H=round(c.Height/(Rad*4))*4
RandomSource(Length=c.FrameCount,Width=W,Height=H,Seed=Seed)
BicubicResize(c.Width,c.Height,1,0)
ConvertToYV12
Limiter(min_luma=16+Y_Lim, max_luma=235-Y_Lim, min_chroma=16+UV_Lim, max_chroma=240-UV_Lim )
return Last
}

SECRET_KEY = 123456789

AviSource("D:\Parade.avi").Trim(1000,-2000).EncryptPrep()
#Return Last

RAD=4
LIM=20
KEY = GenRandomKey(SECRET_KEY,Rad=RAD,Y_Lim=LIM,UV_Lim=LIM)
#Return KEY

ENCRYPTED = MT_Logic(KEY,"xor",y=3,u=3,v=3) # Encrypt
Return ENCRYPTED

# Result of Encypted.Limiter.Decrypt suggests part problem is Illegal YUV colors created by Encryption.
#Return ENCRYPTED.Limiter.MT_Logic(KEY,"xor",y=3,u=3,v=3)

return ENCRYPTED.MT_Logic(KEY,"xor",y=3,u=3,v=3) # Decrypt


Key frame (random)
https://i.postimg.cc/rKTn2DMy/Key.jpg (https://postimg.cc/rKTn2DMy)

Single frame after encrypt
https://i.postimg.cc/r0WcdDDZ/Enc.jpg (https://postimg.cc/r0WcdDDZ)

Encypted.Limiter.Decrypt
https://i.postimg.cc/BjVBbb9K/lim.jpg (https://postimg.cc/BjVBbb9K)

Encypted..Decrypt, same as original
https://i.postimg.cc/LJwQ7Nsw/dec.jpg (https://postimg.cc/LJwQ7Nsw)

EDIT: Actually, the UT_Video compressed Encrypted clip is smaller than the original UT_Video encoded clip
(422MB instead of 432MB, but that might be down to using Limiter on the original clip before encrypting).

EDIT: Changing RAD to 16 produces a rather fancy effect random KEY frame.
https://i.postimg.cc/4dSnLMTw/Fancy.jpg (https://postimages.org/)

and then encrypted
https://i.postimg.cc/KvnpbhsK/FancyEnc.jpg (https://postimages.org/)

spoRv
13th March 2019, 03:10
function deconstruct(clip original, clip modified, Int "Seed" , Int "blk") {
# needs scramble/descramble: https://forum.doom9.org/showthread.php?p=1868405#post1868405
modified
coloryuv(levels="TV->PC")
MT_Logic(original,"xor",y=3,u=3,v=3)
scramble(seed=seed,blk=blk)
}

function reconstruct(clip original, clip deconstructed, Int "Seed" , Int "blk") {
# needs scramble/descramble: https://forum.doom9.org/showthread.php?p=1868405#post1868405
deconstructed
descramble(seed=seed,blk=blk)
MT_Logic(original,"xor",y=3,u=3,v=3)
coloryuv(levels="PC->TV")
}

https://i.postimg.cc/pRRvKpw4/original-modified-decontructed.jpg

WARNING: deconstructed video MUST be lossless/uncompressed; its size could be 50/60% bigger than original clip (using the same compression)

Thanks to StainlessS for his help!
:thanks: