Steganographic Squares


14

Steganographic Squares

งานของคุณคือการใช้สตริงและสร้างNxNภาพที่แสดงถึงสตริงนี้ คุณต้องเขียนอัลกอริทึมที่ใช้ในภาพและเปลี่ยนกลับเป็นสตริงเช่นกัน การให้คะแนนจะรวมจำนวนไบต์ของอัลกอริทึมทั้งสอง:

"เข้ารหัส" อัลกอริทึม + "ถอดรหัส" อัลกอริทึม

คุณควรโพสต์แต่ละรายการแยกกันด้วยจำนวนไบต์สำหรับอัลกอริทึมการเข้ารหัสและถอดรหัสที่แสดงแยกกัน


อัลกอริทึมตัวอย่าง

ตัวอย่างเช่นต่อไปนี้เป็น "การเขียนโปรแกรมปริศนาและการเขียนโค้ดกอล์ฟ" โดยใช้อัลกอริธึม Steganographic ตาม ASCII แบบง่าย ๆ ในช่องสีฟ้า:

#2e7250,#6ea972,#04eb6f,#0fc767,#74ab72,#ee6161
#b73b6d,#1aae6d,#f37169,#bda56e,#1fe367,#e99620
#706450,#0d3575,#146b7a,#4ea47a,#2a856c,#95d065
#3f2d73,#cef720,#bab661,#d1b86e,#f22564,#12b820
#0f3d43,#c86e6f,#1ee864,#a66565,#247c20,#c3bb47
#0e296f,#89d46c,#585b66,#c08f20,#455c20,#136f20

รูปภาพจริง ( ภาพที่สร้างขึ้นโดยอัลกอริทึม)

ภาพเป่าขึ้น

คุณสามารถเห็นช่องสีฟ้าเพียงถือค่า ASCII สำหรับภาพนี้:

50 =  80(P) 72 = 114(r) 6f = 111(o) 67 = 103(g) 72 = 114(r) 61 =  97(a) 
6d = 109(m) 6d = 109(m) 69 = 105(i) 6e = 110(n) 67 = 103(g) 20 =  32( ) 
50 =  80(P) 75 = 117(u) 7a = 122(z) 7a = 122(z) 6c = 108(l) 65 = 101(e) 
73 = 115(s) 20 =  32( ) 61 =  97(a) 6e = 110(n) 64 = 100(d) 20 =  32( ) 
43 =  67(C) 6f = 111(o) 64 = 100(d) 65 = 101(e) 20 =  32( ) 47 =  71(G) 
6f = 111(o) 6c = 108(l) 66 = 102(f) 20 =  32( ) 20 =  32( ) 20 =  32( )

ในขณะที่ส่วนที่เหลือของช่องเก็บค่าที่สร้างแบบสุ่มเพื่อ "เติมชีวิตชีวา" ความหลากหลายของสีในภาพ เมื่อดึงข้อความกลับออกมาจากภาพเราก็สามารถเพิกเฉยค่าช่องอื่น ๆ และดึงบิตฐานสิบหกในช่องสีฟ้าสร้างสตริงใหม่:

"Programming Puzzles and Code Golf"

ขอให้สังเกตว่าช่องว่างที่ใช้ในการวางสายอักขระในสี่เหลี่ยมจะไม่รวมอยู่ในผลลัพธ์ที่ถอดรหัสสุดท้าย ในขณะที่คุณต้องใส่สตริงในภาพคุณอาจสมมติว่าสตริงอินพุตจะไม่ลงท้ายด้วยช่องว่าง


กฎระเบียบ

  • คุณจะต้องเข้ารหัส 1 ตัวอักษรต่อพิกเซลช่องทางที่เลือกให้เข้ารหัสอักขระนั้นเป็นกฎเกณฑ์
  • แชนเนลของสี RGB อื่น ๆ จะต้องทำการสุ่มนอกจากที่คุณเลือกที่จะเข้ารหัสสตริงเข้าไป นี่หมายความว่าแชนเนลที่ไม่ได้เข้ารหัสสุดท้ายของคุณจะต้องอยู่ระหว่าง0x0000-0xFFFF (สุ่มเลือก)
  • การแสดงผลลัพธ์สุดท้ายเนื่องจากอาร์เรย์สี RGB มีค่า 2 มิติ0x000000-0xFFFFFFไม่จำเป็นต้องใช้การสร้างรูปภาพเว้นแต่ว่าคุณต้องการที่จะสนุกกับมันหรือถ้าไบต์น้อย หากคุณเลือกที่จะส่งออกเป็นสตริงฐานสิบหกนำหน้าสตริง hex ด้วย#EG #FFFFFFหรือ#05AB1Eหรือคุณอาจคั่นด้วยแท็บเครื่องหมายจุลภาคหรืออะไรก็ได้ที่จะสมเหตุสมผลในแนวนอน แต่ต้องรักษารูปแบบสี่เหลี่ยม กล่าวอีกนัยหนึ่งคุณต้องใช้การขึ้นบรรทัดใหม่ที่เหมาะสม
  • เอาต์พุตจะต้องอยู่ในรูปสี่เหลี่ยมจัตุรัสและสตริงต้องมีการเว้นวรรคที่ท้ายเพื่อรองรับสิ่งนี้ N≈SQRT(Input#Length())ซึ่งหมายความว่า หากความยาวของอินพุตไม่ใช่สี่เหลี่ยมจัตุรัสที่สมบูรณ์แบบคุณควรปัดเศษขึ้นNและวางแผ่นด้วยช่องว่าง
  • ตามที่ระบุไว้ก่อนหน้านี้หากคุณกำลังขยายช่องว่างในภาพคุณจะต้องไม่รวมอักขระที่มีเบาะรองในผลลัพธ์ "ถอดรหัส" สุดท้าย
  • คุณสามารถสันนิษฐานได้ว่า:
    • สตริงอินพุตจะไม่ลงท้ายด้วยช่องว่าง
    • สตริงอินพุตจะใช้เฉพาะอักขระ ASCII ที่พิมพ์ได้
  • นี่คือ , จำนวนไบต์ต่ำสุดที่ชนะ

เพียงชี้แจงการแก้ปัญหาจะต้องเข้ารหัส / ถอดรหัสว่าตัวละครตัวหนึ่งต่อพิกเซล?
ETHproductions

@ETHproductions ที่ฟังดูเหมือนเป็นความท้าทายในการติดตาม แต่สำหรับจุดประสงค์ของการแข่งขันครั้งนี้คุณเลือกแชนเนลเข้ารหัสและเข้ารหัสอักขระ 1 ตัวต่อพิกเซล
Magic Octopus Urn

ฉันอาจจะไม่ใช้สิ่งนี้ แต่: ตกลงหรือไม่ที่จะ "overpad" ภาพที่มีช่องว่างมากกว่าที่จำเป็น? และมันก็โอเคที่จะสมมติว่าภาพจะมีจำนวนการโอเวอร์แพ็ดเท่ากันกับที่ตัวเข้ารหัสจะสร้างหรือไม่?

@ ais523 ฉันไม่เห็นว่าวิธีการนี้จะทำอะไรได้บ้าง ฉันจะไปด้วยไม่ได้เพราะความท้าทายนั้นเก่าเกินไปที่จะเปลี่ยนแปลงขนาดใหญ่เช่นนั้น
Magic Octopus Urn

1
ใช่ฉันไม่แน่ใจว่าได้รับอนุญาตในคำถามดั้งเดิมแทนที่จะแนะนำการเปลี่ยนแปลงหรือไม่ (ฉันกำลังคิดเกี่ยวกับการบรรจุข้อมูลลงในสี่เหลี่ยมซึ่งง่ายกว่าและอาจคำนวณไบต์พิกัดสั้นกว่าการบรรจุลงในตารางแล้ว padding สี่เหลี่ยมออกสี่เหลี่ยมขนาดใหญ่)

คำตอบ:


2

05AB1E , 34 + 12 = 46 ไบต์

ใช้ช่องสีแดง
05AB1E ใช้การเข้ารหัสCP-1252

เข้ารหัส:

DgDtî©n-Äð×JvyÇh`4F15Ý.Rh«}})'#ì®ä

D                                   # duplicate input
 gDtî©n-Ä                           # abs(len(input)-round_up(sqrt(len(input)))^2)
         ð×J                        # join that many spaces to end of input
            v                       # for each char in string
             yÇ                     # get ascii value
               h`                   # convert to base-16 number
                 4F                 # 4 times do:
                   15Ý.Rh           # push random base-16 number
                         «          # concatenate
                          }}        # end inner and outer loop
                            )       # wrap in list
                             '#ì    # prepend a "#" to each element in list
                                ®ä  # split in pieces round_up(sqrt(len(input))) long

ลองออนไลน์!

Decode:

˜vy3£¦HçJ}ðÜ

˜               # deep flatten input to a list
 v              # for each color in the list
  y3£           # take the first 3 chars
     ¦          # remove the hash sign
      H         # convert from base-16 to base-10
       ç        # get the ascii char with that value
        J       # join to string
         }      # end loop
          ðÜ    # remove trailing spaces

ลองออนไลน์!

วิธีการเสริมทางเลือกที่มีจำนวนไบต์เท่ากับ

Dgð×J¹gtî©n£

ฉันคิดว่าคุณต้องเข้าร่วมในการขึ้นบรรทัดใหม่โดยเฉพาะตามคำถามหรือไม่ (คำตอบของคุณอาจเอาชนะฉันได้แม้ว่ามันจะถูกปรับให้ทำเช่นนั้นเพราะฉันใช้เวลาเพียงห้าไบต์ในการจัดการกับส่วนนั้นของคำถามและคุณก็ล้ำหน้ากว่านั้น)

@ ais523: กฎระบุว่าอาร์เรย์ 2 มิตินั้นโอเค ฉันเข้าใจผิดว่าอย่างใด?
Emigna

"คุณอาจคั่นด้วยแท็บจุลภาคหรือสิ่งอื่นใดที่เหมาะสมในแนวนอน แต่ต้องรักษารูปแบบสี่เหลี่ยมจัตุรัสหรืออีกนัยหนึ่งคุณต้องใช้การขึ้นบรรทัดใหม่ที่เหมาะสม" มันบอกเป็นนัยว่ามันต้องเป็นสตริงเนื่องจากอาร์เรย์ 2 มิติไม่มีการขึ้นบรรทัดใหม่ กล่าวอีกนัยหนึ่งฉันตีความ "อาร์เรย์" ตามที่อธิบายถึงรูปร่างของเอาต์พุตไม่ใช่ชนิดข้อมูลของเอาต์พุต

@ ais523: ฉันขอ OP เพื่อความกระจ่าง อย่างที่คุณพูดมันไม่ได้เป็นการเปลี่ยนแปลงขนาดใหญ่ที่จะนำไปใช้ แต่บางทีคุณสามารถบันทึกไบต์ได้เช่นกันหากไม่ต้องการการจัดรูปแบบ
Emigna

@ ais523 วิธีใดเป็นที่ยอมรับ
Magic Octopus Urn

4

C, 201 (เข้ารหัส) + 175 (ถอดรหัส) = 376 ไบต์

ในการเข้ารหัส:

E(char*J){size_t L=ceil(sqrt(strlen(J)));int U;srand(time(NULL));for(int i=0;i<L;i++){for(int f=0;f<L;f++){printf("#%02X%02X%02X ",rand()%256,(U<strlen(J))?(int)J[U]:32,rand()%256);U+=1;}printf("\n");}}

เข้ารหัสอักขระแต่ละตัวของสตริงป้อนเข้าในช่องสีเขียวของสเปกตรัม RGB ในขณะที่การตั้งค่าอีกสองช่องเป็นค่าเลขฐานสิบแบบสุ่ม รับอินพุตผ่าน STDIN เป็นสตริงและส่งออกไปยัง STDOUT สตริง multiline ของรหัสสีฐานสิบหกในรูปทรงสี่เหลี่ยม สมมติว่าคุณติดตั้ง Python 3 และ ImageMagick และไฟล์ด้านบนถูกคอมไพล์ลงในไฟล์ที่มีชื่อa.outในไดเรกทอรีการทำงานปัจจุบัน (CWD) คุณสามารถรับภาพผลลัพธ์ที่ตั้งชื่อOutput.pngไปยัง CWD โดยตรงจากเอาต์พุตแบบข้อความโดยใช้คำสั่งต่อไปนี้:

./a.out "<Multiline Input>"|python3 -c "import sys,subprocess;Input=sys.stdin.read();print('# ImageMagick pixel enumeration: {0},{0},255,rgb\n'.format(len(Input.split('\n')[1].split()))+'\n'.join(['%d,%d:(%d,%d,%d)'%(g,i,int(j[1:][:2],16),int(j[1:][2:4],16),int(j[1:][4:6],16))for g,h in enumerate(Input.split('\n'))for i,j in enumerate(h.split())]))"|convert - -scale 1000% Output.png

นี่คือรูปภาพเอาต์พุตตัวอย่างที่สร้างโดยคอมมอนด์ด้านบนโดยใช้Programming Puzzles and Code Golfเป็นสตริงอินพุต:

ตัวอย่างผลลัพธ์

เพื่อถอดรหัส:

D(int c,char**U){char T[c];for(int Y=1;Y<c;Y++){char G[2]={U[Y][3],U[Y][4]};T[Y-1]=(char)strtol(G,NULL,16);}int C=c-1;T[C]='\0';while(T[C]==' '){T[C]='\0';C-=1;}printf("%s\n",T);}

จะเข้าผ่าน STDIN ลำดับของพื้นที่แยกสตริงสีรหัสฐานสิบหกกับแต่ละคนล้อมรอบในราคาคู่ ( ") ( char** argvในmain) และเมื่อเรียกmain, int argcสำหรับการป้อนข้อมูลจำนวนเต็ม เอาต์พุตไปยัง STDOUT สตริงเดี่ยว / หลายบรรทัดที่แทนข้อความถอดรหัส

ฉันจะพยายามเล่นกอล์ฟให้มากขึ้นเมื่อเวลาผ่านไปและเมื่อใดก็ตามที่ฉันสามารถทำได้


นอกจากนี้หากคุณเหมือนกันทั้งสองวิธีในไฟล์เดียวกันคุณสามารถใช้mainวิธีการต่อไปนี้เพื่อรวมเข้าด้วยกันโดยแต่ละฟังก์ชันจะได้รับอินพุตที่ถูกต้อง:

int main(int argc,char**argv){if(strcmp(argv[1],"E")==0){Encode(argv[2]);}else{Decode(argc,argv);}}

และการใช้สิ่งนี้สำหรับการเข้ารหัสคุณต้องระบุEเป็นอาร์กิวเมนต์แรกเพื่อเรียกใช้วิธีการเข้ารหัสตามด้วยอาร์กิวเมนต์สตริงเดี่ยวในขณะที่สำหรับการถอดรหัสสิ่งที่คุณต้องเตรียมคือลำดับของสตริงรหัสสีฐานสิบหกที่มีช่องว่างคั่นด้วยแต่ละอัน เครื่องหมายคำพูดคู่ ( ")


สุดท้ายหากคุณต้องการคุณสามารถรับรุ่นที่พร้อมใช้งานที่นี่ได้อย่างเต็มที่แม้ว่าจะไม่ได้เล่นกอล์ฟ แต่ก็ไม่ส่งคำเตือนหรือข้อผิดพลาดใด ๆเมื่อรวบรวม


3

Python 2, 164 160 + 94 93 = 253 ไบต์

บันทึก 1 + 1 ไบต์ด้วย Wheat Wizard

-5 ไบต์ขอบคุณ Kade

รูปภาพเข้ารหัสEncoder: สตริงจะต้องอยู่ในเครื่องหมายคำพูดเช่น"CodeGolf"เอาท์พุทเป็นภาพสี ASCII PPM

from random import*
s=input()
n=int((len(s)-1)**0.5)+1
s=s.ljust(n*n)
r=randint
print"P3 %d %d 255 "%(n,n)+''.join("%d "*3%(r(0,255),r(0,255),ord(c))for c in s)

รูปภาพถอดรหัสถอดรหัส: ใช้ชื่อไฟล์อินพุตเป็นอาร์กิวเมนต์บรรทัดคำสั่ง

from sys import*
print''.join(chr(int(c))for c in open(argv[1]).read().split()[6::3]).strip()

การใช้งาน:

 python golf_stegansquare_enc.py > stega.ppm

 python golf_stegansquare_dec.py stega.ppm

ตัวอย่าง:

การเขียนโปรแกรมปริศนาและรหัสกอล์ฟการเขียนโปรแกรมปริศนาและรหัสกอล์ฟ

Lorem Ipsumสิ่งที่น่าสนใจมากคือการนั่งอยู่บนเก้าอี้ที่ทำด้วยมือ, งานฝีมือที่ทำจากไม้, งานฝีมือที่ทำจากโลหะ, งานฝีมือและงานฝีมือ, งานฝีมือและงานฝีมือ ที่ Vero eos และ accusam และ justo duo dolores และ ea rebum คลิกที่นี่เพื่อรับเงิน, ไม่มีทะเล takimata sanctus เป็น Lorem ipsum dolor นั่งอยู่. สิ่งที่น่าสนใจมากคือการนั่งอยู่บนเก้าอี้ที่ทำด้วยมือ, งานฝีมือที่ทำจากไม้, งานฝีมือที่ทำจากโลหะ, งานฝีมือและงานฝีมือ, งานฝีมือและงานฝีมือ ที่ Vero eos และ accusam และ justo duo dolores และ ea rebum คลิกที่นี่เพื่อรับเงิน, ไม่มีทะเล takimata sanctus เป็น Lorem ipsum dolor นั่งอยู่.


คุณสามารถลบช่องว่างระหว่างวงเล็บใกล้แล้วfor
โพสต์ร็อคฮันเตอร์ Garf

@ETHproductions: sqrt (25-1) = sqrt (24) <5 และ> 4. intจากนี้คือ 4 ซึ่งเป็น+1ed ดังนั้น 5
Karl Napf

-1โอ้ไม่ดีของฉันฉันไม่เห็น
ETHproductions

1
คุณสามารถลบช่องว่างระหว่างprintและ'ในตัวถอดรหัส ฉันค่อนข้างมั่นใจว่าคุณสามารถทำได้int((len(s)+1)**.5)เพื่อบันทึกบางไบต์
Kade

1
ฉัน redacting ประโยคสุดท้ายของความคิดเห็นก่อนหน้าของฉัน แต่คุณสามารถย่อการพิมพ์โดยการเปลี่ยน' '.join("%d %d %d"เป็น''.join(3*"%d "เพราะฉันค่อนข้างมั่นใจว่าพื้นที่ต่อท้ายคือตกลง
Kade

2

สกาลา, 97 + 68 = 165 ไบต์

การเข้ารหัส (97 ไบต์):

s=>s.map(_+((math.random*65535).toInt<<8)).iterator.grouped(math.sqrt(s.size)toInt)withPadding 32

รับสตริงและ retuns Iterator ของ Sequences of Integers

การถอดรหัส (68 ไบต์):

a=>" +$".r.replaceAllIn(a.flatten.map(h=>(h&0xFF)toChar)mkString,"")

รับ Iterator ของ Sequences of Integers และส่งคืนสตริง

คำอธิบาย:

s=>                         //define an anonymous function
  s.map(                      //map each char of the string
    _+(                         //to the ascii value plus
      (math.random*65535).toInt)  //a random integer between 0 and 65535
      <<8                         //shifted 8 bits to the left
    )
  )
  .iterator                     //create an iterator
  .grouped(                     //group them in groups of size...
    math.sqrt(s.size)toInt        //sqrt of the size of the input, rounded up
  )withPadding 32               //pad with spaces to make a square

.

a=>
  " +$"              //take this string
  .r                 //parse it as a regex
  .replaceAllIn(     //replace every occurence of the regex in...
    a.flatten          //a flattened
    .map(h=>           //each element mapped
      (h&0xFF)toChar)    //to the character of the lower 8 bits
    mkString,          //joined to a string
    ""               //with an empty string
  )

2

Perl, (103 + 1) + (36 + 2) = 142 ไบต์

ตัวแปลงข้อความเป็นรูปภาพ (เรียกใช้ด้วย-pการลงโทษแบบ 1 ไบต์-p0(สำหรับการลงโทษเพิ่มเติมแบบไบต์) เป็นสิ่งจำเป็นหากคุณต้องการจัดการบรรทัดใหม่ในสตริงอินพุต):

$_.=$"while($a=(length)**.5)=~/\./;$_=unpack"H*";s/../sprintf"#%04x$&,",rand+4**8/eg;s/(.*?\K,){$a}/
/g

Image to text decoder (รันด้วย-p0การลงโทษ 2 ไบต์):

$\.=chr hex for/..\W/g;$\=~s/ *$//}{

สิ่งนี้ใช้รูป#abcdefแบบข้อความตามข้อความและเข้ารหัสในช่องสีฟ้า นี่คือตัวอย่างของเอาต์พุตที่เป็นไปได้ที่กำหนดProgramming Puzzles and Code Golfเป็นอินพุต:

# b4d250 # bccb72 # 43f06f # 4d6767 # 74ba72 # 269461
# e4f26d # f63d6d # 701c69 # bbf56e # 6ef967 # d78d20
# 4e0d50 # 9b2775 # afd37a # 12a47a # 63e46c # 0e9565
# 4cad73 # e43420 # 6da761 # 5a306e # 8fba64 # 58f720
# d52443 # b4446f # fbaf64 # 4a4365 # 1a5020 # f3ea47
# 354c6f # 52cb6c # 11a766 # 4c380a # 553820 # b31120

คำอธิบายของการเข้ารหัส:

$_.=$"             # append a space ($") to the input ($_)
  while            # as long as the following condition holds:
(($a=length)**.5)  # the square root of the input length (save this in $a)
=~/\./;            # has no decimal points in its string represenation
$_=unpack"H*";     # convert the input from base-256 to hexadecimal
s/../              # replace two characters of the input
  sprintf          # with a string formed from the template
  "#%04x$&,",      # four hex digits, the two matched characters, and a comma
  rand+4**8        # those hex digits are a random number from 0 to 4**8 (= 65536)
/eg;               # and do this for every non-overlapping match
s/(.*?             # find the minimum number of characters needed to match
   \K,)            # replacing the part of the match after the last matched comma
  {$a}/            # a string containing $a commas
/gx                # with a newline, for every non-overlapping match

ผมก็ใช้นี้มีความสุขจริงๆ\Kทำงาน; มันระบุตำแหน่งที่จะแทนที่และวางไว้ในลูปดูเหมือนว่าการวนซ้ำของลูปสุดท้ายคือสิ่งที่นับ ดังนั้นs/(.*?\K,){$a}/\n/gจะจับคู่สตริงที่มีความยาวต่ำสุดของฟอร์มอะไรเครื่องหมายจุลภาคอะไรเครื่องหมายจุลภาค ... อะไรเครื่องหมายจุลภาคที่มี$aเครื่องหมายจุลภาค แต่ส่วนที่แทนที่จริงของการแข่งขันจะเป็นเครื่องหมายจุลภาคสุดท้าย สิ่งนี้มีผลในการแทนที่$aเครื่องหมายจุลภาคทุกอันด้วยการขึ้นบรรทัดใหม่ทำให้เรามีรูปทรงสี่เหลี่ยมสำหรับภาพ

ข้อได้เปรียบที่ยิ่งใหญ่ของ Perl สำหรับความท้าทายนี้ (นอกเหนือจากตัวแปลงสตริงเป็นตัวเลขฐานสิบหกในตัวซึ่งสะดวกสบายอย่างเหลือเชื่อ) คือมันมีตัวถอดรหัสที่สั้นมาก ๆ การแปลงเลขฐานสิบหกให้เป็นสตริงจะสั้นกว่าที่จะไม่ใช้) นี่คือวิธีการทำงาน:

$\.=chr      # append to $\ the character code
  hex        # of the hexadecimal-string-to-number-translation
for/..\W/g;  # of each two characters that appear before a
             # non-alphanumeric character (not counting overlapping matches)
$\=~s/ *$//  # delete all spaces at the end of $\
}{           # in this context, this means "implicitly print $\,
             # prevent any other implicit printing"

อินสแตนซ์เดียวของอักขระสองตัวก่อนหน้าอักขระที่ไม่ใช่ตัวอักษรและตัวเลขคือช่องสีฟ้า (ซึ่งเราต้องการแยกออก) ซึ่งจะปรากฏก่อนคอมม่าและบรรทัดใหม่ และอักขระสองตัวที่ปรากฏต่อหน้าซึ่ง#ไม่ใช่อักขระแรก เราไม่ต้องการหมวดหมู่การแข่งขันหลัง แต่พวกเขาซ้อนทับหมวดหมู่เดิมอย่างหลีกเลี่ยงไม่ได้และจะถูกยกเว้นโดยการตรวจสอบการแข่งขันที่ทับซ้อนกัน


1

MySQL, 438 + 237 = 675 ไบต์

มีบรรทัดใหม่ต่อท้ายที่ส่วนท้ายของเอาต์พุต แต่จะไม่แสดงขึ้นหลังจากถูกถอดรหัส ฟังก์ชั่นฐานสิบหก (จำนวนเต็มจำนวนเต็ม) จะตัดส่วนที่นำหน้า 0 ดังนั้นฉันจึงต้องวางด้วยสตริง 0 ฉันสามารถบันทึกบางไบต์ถ้าฉันสามารถประกาศฟังก์ชั่นทั้งสองระหว่างตัวคั่น

การเข้ารหัสลับ

delimiter //create function a(i text)returns text begin declare r int;declare q,p text;while mod(length(i),sqrt(length(i)))<>0 do set i:=concat(i,' ');end while;set r:=1;set q:="";while r<=length(i) do set p:=",";if mod(r,sqrt(length(i)))=0 then set p:="\r\n";end if;set q:=concat(q,'#',right(concat(0,hex(floor(rand()*256))),2),right(concat(0,hex(floor(rand()*256))),2),hex(mid(i,r,1)),p);set r:=r+1;end while;return q;end//
delimiter ;

ถอดรหัส

delimiter //create function b(i text)returns text begin declare x int;declare y text;set x:=0;set y:="";while instr(i,'#')>0 do set i:=substr(i,instr(i,'#')+5);set y:=concat(y,unhex(left(i,2)));end while;return trim(y);end//
delimiter ;

การใช้งาน:

select a('test')
select b('#7D1874,#FFB465')
select b(a('test'))

1

C #, 312 + 142 = 454 ไบต์

การเข้ารหัส:

using System;I=>{var r=new Random();int i=I.Length;int N=(int)Math.Floor(Math.Sqrt(i))+1,S=N*N;while(i++<S){I+=' ';}var R="";for(i=0;i<S;){R+=i%N<1&i>0?"\n":i<1?"":" ";R+="#"+r.Next(256).ToString("X").PadLeft(2,'0')+r.Next(256).ToString("X").PadLeft(2,'0')+((int)I[i++]).ToString("X").PadLeft(2,'0');}return R;};

ถอดรหัส:

using System;I=>{var s=I.Replace('\n',' ').Split(' ');var R="";foreach(var t in s)R+=(char)System.Convert.ToInt32(t[5]+""+t[6],16);return R.TrimEnd(' ');};

โปรแกรมเต็มรูปแบบ:

using System;
class Steganographic
{
    static void Main()
    {
        Func<string, string> E = null;
        Func<string, string> D = null;

        E=I=>
        {
            var r=new Random();
            int i=I.Length;
            int N=(int)Math.Floor(Math.Sqrt(i))+1,S=N*N;
            while(i++<S){I+=' ';}
            var R="";
            for(i=0;i<S;)
            {
                R+=i%N<1&i>0?"\n":i<1?"":" ";
                R+="#"+r.Next(256).ToString("X").PadLeft(2,'0')+r.Next(256).ToString("X").PadLeft(2,'0')+((int)I[i++]).ToString("X").PadLeft(2,'0');
            }
            return R;
        };

        D=I=>
        {
            var s=I.Replace('\n',' ').Split(' ');
            var R="";
            foreach(var t in s)
                R+=(char)Convert.ToInt32(t[5]+""+t[6],16);
            return R.TrimEnd(' ');
        };

        string encoded = E("Programming Puzzles and Code Golf");
        Console.WriteLine(encoded);
        Console.WriteLine(D(encoded));

        encoded = E("Hello, World!");
        Console.WriteLine(encoded);
        Console.WriteLine(D(encoded));

        Console.Read(); // For Visual Studio
    }
}

1

Mathematica, 111 + 65 = 176 ไบต์

Encoder

Join[255~RandomInteger~{n=⌈Sqrt@Length@#⌉,n,2},ArrayReshape[#,{n,n,1},32],3]~Image~"Byte"&@*ToCharacterCode

ถอดรหัส

StringTrim[""<>FromCharacterCode@ImageData[#,"Byte"][[;;,;;,3]]]&

1

กำลังดำเนินการ, 220 209 194 + 171 167 151 = 391 380 376 361 345 ไบต์

ปรับปรุง:

นำไร้ประโยชน์ออกnoStroke()และทำให้ทั้งสองลูปแบบหนึ่ง -claimers

ลบไร้ประโยชน์image(p,0,0);ให้ decryptor ชื่อไฟล์เป็นพารามิเตอร์

อัลกอริทึมการเข้ารหัส

void g(String h){int s=ceil(sqrt(h.length()));for(int y=0,x;y<s;y++)for(x=0;x<s;rect(x,y,1,1),x++)stroke(h.length()>y*s+x?h.charAt(y*s+x):32,random(255),random(255));get(0,0,s,s).save("t.png");}

การเรียกใช้ฟังก์ชัน: g("Programming Puzzles and Code Golf");

t.pngนี้เป็นฟังก์ชั่นที่ใช้ในสตริงและสร้างการส่งออกก่อนที่จะบันทึกเป็น มันใช้redค่าในการจัดเก็บข้อความที่ซ่อนอยู่

อัลกอริทึมถอดรหัส

void u(String f){PImage p=loadImage(f);f="";for(int j=0,i;j<p.height;j++)for(i=0;i<p.width;i++)f+=(char)red(p.get(i,j));print(f.replaceAll(" +$",""));}

ฟังก์ชั่นการโทรโดย: u(file_name);

นี่เป็นฟังก์ชันที่ค้นหารูปภาพที่ระบุโดยพารามิเตอร์จากนั้นส่งออกสตริงที่ซ่อนอยู่ (เนื่องจากสั้นกว่าการส่งคืนสตริง)

รหัสขยาย

(อัลกอริทึมการเข้ารหัส)

void g(String h) {
  int s=ceil(sqrt(h.length()));
  for(int y=0,x;y<s;y++)
    for(x=0;x<s;rect(x,y,1,1),x++)
      stroke(h.length()>y*s+x?h.charAt(y*s+x):32,random(255),random(255));
  get(0,0,s,s).save("t.png");
}

สตริงจะถูกส่งผ่านเมื่อเรียกใช้ฟังก์ชัน บรรทัดแรกของฟังก์ชั่นคำนวณความยาวด้านของสี่เหลี่ยมจัตุรัสโดยการหาสceilแควร์รูท จากนั้นเราป้อน for-loop โดยที่เราตั้งค่าstroke(สีของขอบ) เพื่อให้ค่า ASCII ของตัวละครเป็นสีแดงและค่าสุ่มสำหรับสีน้ำเงินและสีเขียว หลังจากที่เราทำเช่นนี้เราได้สร้างrect(สี่เหลี่ยมผืนผ้า) พร้อม width = 1และ height = 1เช่นพิกเซล (ด้วยเหตุผลแปลก ๆ บางอย่างฉันไม่สามารถใช้งานpointได้อย่างถูกต้อง) t.pngในบรรทัดสุดท้ายภาพที่เกิดจะถูกบันทึกไว้แล้ว

(อัลกอริทึมถอดรหัส)

void u(String f) {
  PImage p=loadImage(f);
  f="";
  for(int j=0,i;j<p.height;j++)
    for(i=0;i<p.width;i++)
      f+=(char)red(p.get(i,j));
  print(f.replaceAll(" +$",""));
}

ฟังก์ชั่นนี้มีชื่อของไฟล์เป็นพารามิเตอร์ (เป็นสตริง) จากนั้นภาพในไฟล์จะถูกเก็บไว้ในตัวแปรที่จะใช้ในภายหลัง หลังจากเราทำเสร็จแล้วเราจะตั้งค่าสตริงเป็น""แทนที่จะสร้างสตริงใหม่เพื่อเก็บสตริงที่ซ่อนไว้ จากนั้นเราวนซ้ำของภาพผ่านสองลูปซ้อนกันสำหรับลูปและเราจะใส่ค่าอักขระของค่าสีแดงของพิกเซลลงในสตริง สุดท้ายเราพิมพ์สตริงผลลัพธ์หลังจากลบช่องว่างนำออกจากมัน (ใช้ regex) เหตุผลที่เราพิมพ์ข้อความที่ซ่อนไว้แทนที่จะกลับมาเป็นเพราะวิธีนี้จะสั้นกว่าและเราบันทึกไบต์


เข้ารหัสข้อความดิบที่ท้าทาย:

ป้อนคำอธิบายรูปภาพที่นี่


1

เยลลี่ 40 + 20 = 60 ไบต์ในหน้าเพจของเจลลี่

เข้ารหัส (ข้อความ→ภาพ):

”#;;ØHX¤¥4¡
»⁶x⁹²¤¤Ob⁴‘ịØHÇ€sj€”,Y
L½Ċç@

ลองออนไลน์!

ถอดรหัส (รูปภาพ→ข้อความ):

ḣ2ØHiЀ’ḅ⁴Ọ
ṣ”#Ç€œr⁶

ลองออนไลน์!

ตัวอย่างผลลัพธ์ที่โปรแกรมสามารถสร้าง (เก็บข้อมูลในช่องสีแดง):

#504219,#720200,#6F38F1,#67055F,#7228C7,#61AC95
#6DD797,#6D20CB,#6962FA,#6E69B1,#67C41C,#209436
#50CB19,#75C9FC,#7A1B06,#7A695B,#6C5D5B,#6539A6
#735925,#20C80F,#612C38,#6EBF9E,#64C79E,#200915
#4337C5,#6F4704,#64FB5F,#65B2D1,#20E075,#47BC7C
#6F0C16,#6CD8EF,#66060B,#203C6C,#20D6E9,#20C0D7

ในความท้าทายที่ยิ่งใหญ่เหล่านี้ความอดทนของเยลลี่ก็เริ่มลดลงเล็กน้อยต้องการตัวละคร "โครงสร้าง" หลายตัวเพื่อแก้ไขความคลุมเครือในการแยกวิเคราะห์ แต่มันก็ยังสั้นเกินไป นี่คือการทำงานของโปรแกรมเปลี่ยนไฟล์:

Subroutine 1: convert digits to randomly padded hex string
”#;;ØHX¤¥4¡
”#;                     prepend #
    ØHX                 random hexadecimal digit
       ¤                parse ØH and X as a unit
   ;                    append
        ¥               parse ; and ØHX¤ as a unit
         4¡             repeat four times

Subroutine 2: convert string λ to square with size ρ
»⁶x⁹²¤¤Ob⁴‘ịØHÇ€sj€”,Y
 ⁶                      space
   ⁹²                   ρ squared
     ¤                  parse ⁹² as a unit
  x                     repeat string (i.e. ρ² spaces)
      ¤                 parse ⁶x⁹²¤ as a unit
»                       take maximum
Because space has the lowest value of any printable ASCII character,
this has the effect of padding λ to length ρ² with spaces.
       O                take codepoints of string
        b⁴              convert to base 16
           ịØH          use as indexes into a list of hexadecimal digits
          ‘             0-indexed (Jelly uses 1-indexing by default)
              ǀ        run subroutine 1 on each element
                s       split into groups of size ρ
                  €     inside each group
                 j ”,   join on commas
                     Y  join on newlines

Main program: basically just calculates ρ and lets subroutine 2 do the work
L½Ċç@
L                       length of input
 ½                      square rooted
  Ċ                     rounded up to the next highest integer
   ç@                   call subroutine 2 with the original input and the above

และนี่คือการทำงานของตัวถอดรหัส:

Subroutine: convert hexadecimal color string (without #) to character
ḣ2ØHiЀ’ḅ⁴Ọ
ḣ2                      take first two characters
  ØHi                   find indexes in a string of hexadecimal digits
     Ѐ                 for each of those characters
       ’                0-indexed (Jelly uses 1-indexing by default)
        ḅ⁴              convert from base 16
          Ọ             convert integer to character

Main program:
ṣ”#Ç€œr⁶
ṣ”#                     split on # signs
   ǀ                   run the subroutine for each element
     œr⁶                remove spaces from the right
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.