第2章 软件——计算机的灵魂
法律要点 软件侵权中的同一性比对
源代码和经过编译后的可执行程序是“一体两面”的关系,技术上和法律上都将其看作同一个作品是没有问题的,但实践中的问题比较复杂,有些时候权利人更加看重对源代码的保护,另外一些时候则看重源代码执行后在用户客户端上的具体呈现,而且技术上完全可以做到不同的源代码实现相同的执行结果,特别是游戏等复合型软件作品,在侵权比对过程中的同一性判断就变成一个比较复杂的问题了。
想了很久,该怎么样给法律人把计算机和网络相关的技术比较系统和形象化地介绍出来,这里面的难点就在于从哪里开始,因为计算机整个技术的知识体系是比较复杂的,它本身就是一个多学科交叉的综合领域,并不像单一学科那样有着一以贯之的逻辑体系。
最终决定还是从软件入手,因为软件是计算机的灵魂,就像人一样,人的身体就是硬件,软件则相当于人的思维。
此外,对于多数没有理工科背景的法律人来讲,直觉上也都存有一个巨大的疑问:计算机是怎样听懂人的指令和语言的呢?如果了解了软件的基本原理,大概就能够解开这个谜题了,而且搞清楚这一点,将是人类走近机器、跟机器协作的重要前提。
一、计算机如何“思考”
我们知道人跟人之间是借助语言和文字来进行交流的。比如,我写了一个“鱼”字,你看到这个字就会想到一条鱼,这个机制是因为人的大脑具有把符号转化成为形象的思维能力。
但是计算机不会有这种抽象的能力,看到一个“鱼”字不会联想到一条活鱼,虽然说电脑有一个“脑”字,但是电脑跟人脑的思维方式还是不一样的,计算机虽然也有语言,但是跟人的语言文字并不是一回事。
说起计算机的语言,你可能第一时间能够想象出来的场景,就是黑客类电影中出现的画面,黑客坐在那里,手指上下翻飞敲出一行行代码,这些代码的确就是我们最常见的计算机语言。
但是这些语句看上去很令人费解,仔细看它们是由一些英文写成的,我们把这样的语言编成一个程序、一段代码放到计算机里,计算机就能够读懂吗?这个很奇怪,这个过程到底是如何实现的?本章就要把这个问题讲清楚。
我们首先抽取出一段最简单的代码,这是一个由7行代码组成的简单程序,它的作用就是实现在屏幕上打出“Hello World!”这行单词,但是你看这个程序的组成很有代表性,它引用了一个函数:#include <stdio.h>,相当于叫了一个外援,然后构建了一个主函数:int main(用于实现程序的核心功能),主函数中最关键的就是高亮颜色标出的第5行。
printf是一个计算机语言指令,用于让计算机在屏幕上把一个东西显示出来,显示的内容就是括号里的“Hello World!”。而“return 0”的意思是这个函数到此就执行完毕。
这样一解释,相信你是能够明白的,因为这本来就是给人用的计算机语言,我们叫作“高级语言”,但计算机看了之后表示很晕,因为它没有这么“高级”的抽象思维能力,它的思考方式简单粗暴,因为它真正能看懂的只有“0”和“1”。“0”和“1”组成的语言是计算机自己的语言,我们叫作“机器语言”。
那为什么我们用高级语言写出来的程序,计算机还是能够执行呢?这就涉及高级语言是能够向机器语言转化的,下面咱们一点一点深入介绍。
如下图,右边这半部分看到的机器语言由很多的0和1数字组成,这些数字跟人使用的高级语言之间存在对照关系。
左边的语言给人看,右边的语言给机器看,那么接下来就要解释机器为什么只认识“0”和“1”。我们都知道机器的大脑叫作CPU,这个硬件是机器看懂语言的关键,所以我们就要明白CPU的架构到底是什么?法律人都知道有《集成电路布图设计保护条例》,这个条例其实主要针对的就是类似于CPU这样的超大规模集成电路(又叫“芯片”),它里面集成了非常多的基础电路单元,多达几千万和上亿量级,所以叫超大规模集成电路。
如果我们拆开CPU看里面的每一个基本电路单元,就会发现它是一个叫作二极管的东西(这里就简单忽略一些技术细节,可能还有三极管或者其他元器件),二极管就是一个最基本的物理电路,这个电路的特点是首先它只允许电流单向流动,其次它只允许高出一定电压的电流流过去。所以这就意味着在这个电路里面只会存在两种状态,就像一个电灯泡要么亮要么灭,但是不会存在其他第三种状态,如非常亮,或者一般亮,而不会有这种中间的过渡状态。
所以二极管这样一个基本电路单元的作用就是根据电流的接通和断开来实现高低电平两种状态,那么这两种状态刚好就对应到了数字上面的0和1。至此,我们在底层的物理结构上实现了与数字(二进制代码)的对应:CPU认识了0和1。
所以,CPU可以理解为集成了无数个“0-1”状态的运算单元,每个单元都可以呈现0和1两种状态,然后当它有数千万个甚至上亿个这样的“0-1”状态的时候,就可以出现无数个0和1的组合,这就是CPU的基本原理。
二、计算机如何学会“识文断字”
接下来就是第二个最核心的问题了,如果说CPU里面实现的就是无数的0-1组合的话,那么这些组合真的会生成那么多的信息吗?这些0和1又是如何与高级语言对应起来的呢?
我们在计算机里面看到无数种信息,有文字、声音、图片、视频,难道它们都能转化成0和1吗?这个问题就很有意思了,甚至可以上升到哲学的高度,不由得令人想起老子在《道德经》里说的“道生一,一生二,二生三,三生万物”。
老子的这句话使他越看越像是一个伟大的科学家,他竟然在那个时候就想到了如果你有0和1,你可以生发出万物,可以生发出所有的信息,这一点在数千年后的现代计算机科学上得到了印证。
其实计算机(包括手机和电脑等所有智能设备)就为人类做两件事:一是给你呈现出信息,二是把这些信息做运算和处理。比如,你打开PPT的某一页,这是一个信息呈现,当你按“播放下一页”按钮的时候,计算机开始把PPT的下一页调出来呈现在屏幕上,这背后是机器在做运算。
细胞分裂[1]
无论是信息的呈现还是运算,背后都是靠对0和1的识别跟处理。我们先看信息的呈现:
譬如我们在电脑里常见的这些字符,有一个国际标准的字符代码表,其中字符“0”对应的是高四位“0011”和低四位“0000”共计八位0-1代码。
也就是说你给计算机一个八位二进制0-1代码:“00110000”,计算机就给你呈现一个字符“0”,其他字符以此类推,如“@”字符对应的0-1代码是“01000000”。所以等于是把人常用的每一个字符和符号都做了0-1编码,通过八位不同的0-1组合,就可以把ABCD、1234、标点符号等都编好了,我们现在所有的输入设备中都按照这套逻辑编码,不管你敲哪个键,CPU对应接到的一个指令都是八位的0-1组合,至此计算机认识了字符,就像一个幼儿园小朋友开始认识了几个简单的数字和字母一样。
从这个原理继续推而广之,CPU认识了更复杂的信息类型,因为最终所有的文字都不过是基本字符的组合而已,更复杂的声音、图像等也都同理进行了0-1编码(声音无非是音节、音色等元素的组合,图像无非是像素的组合)。我们下载一个电影时说这个电影文件大小有1个G,为什么会有一个文件大小的说法?是因为这个电影被最终编成0-1代码,而这个代码在电脑硬盘中是要占据存储空间的。
1个G就意味着文件由非常多的0和1组成,影片中含有的信息量大自然需要转化成更多的0和1,而一张图片通常就不需要这么多0和1来展示,所以图片大小几M就够了(1G=1024M)。
我们还知道发送大的文件之前要压缩一下,但是压缩完了之后可能图片、视频就不太清楚了,这是为什么?比如,原来文件里面有100万个0和1的组合,压缩的时候会把其中一些不重要的0和1信息剔除掉,于是从100万就变成了50万或者是30万的0和1,因为0和1少了,那么文件的体积肯定就会小了,但同时这也导致压缩后的文件会失真,因为你的信息丢失掉了。
所以说在信息的呈现层面,不论我们在电脑上看到什么东西,在计算机的底层都是当作0和1来进行处理的。
三、计算机如何学会“运算”
说完信息的呈现,再看信息的运算。计算机更大的功能是要做处理和运算,我们平时去写一个PPT、一个Word,播放一个视频,背后都是要CPU和内存来执行这些程序、对我们的输入操作进行不断的运算和处理。
常用数制的对应关系
信息运算跟信息的呈现相比就更复杂了,靠着一堆0和1,怎么来实现运算呢?首先,运算包括算数运算(加减乘除以及更复杂的数学计算)和逻辑运算(是非对错的逻辑判断),算数运算靠0和1二进制数字非常容易就可以转化成我们平时常用的十进制数字,所以算术运算对计算机没有任何障碍。
逻辑运算的实现对计算机而言是一道难题,这里需要引入一门单独的学科叫作“逻辑代数”,由科学家布尔创立,所以又叫“布尔代数”。这门神奇的学科基于0和1两种最原始的状态推演出所有的逻辑结果,或者说所有的逻辑运算、判断都可以通过0和1两种状态最终叠加推导出来。
“逻辑代数”把0和1看作两种逻辑状态,法律人对此可以这么理解。比如,1可以代表“是”,0代表“否”;1可以代表“有”,0代表“无”;1可以代表“有罪”,0代表“无罪”;1可以代表“正义”,0代表“邪恶”等。
逻辑运算概览
当0和1两种状态进行叠加推演的时候,一个无限可能的逻辑世界就此展开。比如,我们把规则设置成:1和0在一起的时候结果还是0;0和0在一起还是0;只有1和1在一起才是1。用这个逻辑规则就可以带入到法律场景中作判断。如必须同时满足“法律规定欠债还钱”的状态=1,同时“我欠了你的钱没有还”的状态=1,此时逻辑运算结果才是“法院判决我要还钱”的状态=1。如果前面法律规定和我欠钱不还的事实中的任何一个状态=0,法院都不可以判我还钱,也就是说此时“法院判决我要还钱”的状态=0。
将这个判断逻辑用计算机高级语言编写为程序就是:
if欠债还钱=法律规定;
if张三欠钱没有还;
then张三必须还钱;
else张三不必还钱。
总而言之,有了0和1这两种底层的逻辑再加上“逻辑代数”确立的运算规则,就可以推衍出无数非常复杂的逻辑判断,而机器就是通过这种方式接收你的逻辑指令,然后得出逻辑运算的结果。
四、越过人和机器之间的语言鸿沟
至此,计算机可以把所有的信息抽象成0和1,把所有的运算也抽象成0和1,于是0和1就成了计算机的语言(机器语言)。而我们人类怎么可能理解和记住那么多的0和1,人类语言(高级语言)跟机器语言之间显然隔着一道鸿沟,怎么办?
这中间就需要一个桥梁,这个桥梁叫作“汇编语言”。它负责把人类的自然语言(高级语言)翻译成机器能看明白的机器语言,所以汇编语言起到一个翻译的作用。
汇编语言的存在使我们放心地用自己看得懂的语言书写计算机代码,然后交给汇编语言编译成机器能看懂的0-1代码,最后交给CPU和内存去把代码执行和运算出来,最终机器就可以了解我们的需要,来帮我们干活了,这就是计算机语言的全部原理。
这张图很好地展示了计算机逻辑语言被硬件理解和执行的过程
我们用计算机语言编写出一个能实现完整功能的代码之后,这段代码理论上就叫作一个程序了。就像我们一开始的时候给大家看的那段让计算机打印“Hello World!”在屏幕上的程序。
一个程序经过汇编语言的编译,封装好之后拿去安装到对应的硬件上,这个时候就可以被称为“软件”了。软件往往是一组程序的集合,而程序就是由计算机语言来编写的,计算机语言又包括高级语言、汇编语言和机器语言,这些基本概念我们算是介绍完毕了。
事实上当我们向计算机发出一个指令的时候,计算机通过软件理解和执行指令,然后转化成了CPU看得懂的0和1,最终算出你想要的东西再展示到屏幕上,这就是软件在人机交互中的价值,所以我说软件是计算机的灵魂。
法律问题
有了上面的技术背景之后,我们有必要看一下法律上对软件是怎么定义的。《计算机软件保护条例》第2条规定,软件指的是计算机程序及其有关的文档。第3条又进一步规定,计算机程序是指为了得到某种结果而可以由计算机等具有信息处理能力的装置执行的代码化指令序列,或者可以被自动转化成代码化指令序列的符号化指令序列或者符号化的语句序列。
第3条的规定非常绕口,主旨就是计算机程序包括两种形态:(1)“代码化指令序列”,也就是机器能看懂的由0和1组成的程序(“可执行程序”“目标程序”,包括程序语句本身和这些语句存放在内存中的位置等,以便CPU可以知道去哪里寻找到相关的指令以及如何执行这些指令);(2)“符号化指令序列”或“符号化语句序列”,也就是人类用高级语言C、JAVA等写成的计算机程序(源程序),其特点是可以自动被转化成代码化指令序列,即0-1形式的可执行程序。
这两种指令序列都是计算机程序,只不过使用的语言不同、面向的主体不同(前者为人,后者为机器)而已,所以《计算机软件保护条例》规定“同一计算机程序的源程序和目标程序为同一作品”。举一个形象但不严谨的例子,源程序和目标程序就像一部小说的中文版和英文版。
这样的法律规定也带来了一些问题:
首先是软件代码公开导致的软件专利或商业秘密性问题。一个软件写好了之后,源程序通常是不对外公布的,而是把源程序直接编译成一个可执行的目标程序,然后交付用户安装使用。这时如果法律认为二者是同一作品,是不是我只要把目标程序向用户交付就意味着我同时公开了源程序?
在很多情况下,开发者既要把这个软件开发出来尽快上市发行,又想把源代码相关的一些技术能够注册成专利或者作为商业秘密保护起来,那会不会由于发行了这个目标程序,而使得想要保护的专利和技术秘密被公开了,丧失了所谓的新颖性、秘密性,进而难以取得著作权之外的保护。这是个目前在实务界、学术界都有很大争议的问题。
对此,笔者个人的看法是,可执行程序的上市流通并不能代表源程序的公开,因为法律规定的二者属于同一作品是在著作权意义上的、对作品的同一性判断上的规定,并不涉及软件技术细节是否公开的问题。后者是一个事实问题,事实上用户拿到了可执行程序也无法推断出背后的源代码,所以源代码仍然处于没有被公开的状态,不影响其作为技术创新的一部分成为专利或商业秘密保护的对象。
其次是软件侵权的同一性比对问题。
比如,我开发出来的软件被对方抄袭了,就像我写了一本书被对方抄袭一样,要有一个同一性的对比,比较一下两个作品是否一致。
当前,流传着一种说法是,软件同一性比对要看相同代码的百分比,超过80%就认为是侵权(也有说70%)。这种理解跟司法实践是有偏差的,实践中对软件同一性的比对不会采用一个固定的比例,因为计算机的源代码很多是模块化的(前辈们已经写好了),你只是直接把它拿过来用,尤其是一些通用的功能(如分享功能)等,要么是第三方写好的,要么是系统或者程序本身自带的一些函数库里面就有的。
调用这样的一些现成的代码就会导致你的程序跟其他人的程序产生很大部分的重合,但是并不代表你在抄袭别人,因为你的代码中体现的软件核心功能或价值的部分必定是你独创出来的。所以这种软件源代码的比对还是应该一事一议地在个案中去认定。
那么一般来讲,从鉴定机构的角度来看,它们在进行软件同一性比对的时候主要看一些什么呢?
(1)代码中有独创性的部分。把市面上通用的一些模块拿掉之后再比较,看哪些代码是有独创性的,这个独创的部分有无抄袭。
(2)软件的标注信息。包括软件的签名、注释、权利人信息等,这些信息都是非常个性化的,并且有着比较明确的身份指向,如果抄袭的时候不注意把这些内容也一起复制粘贴过去了,就很容易认定存在抄袭;在软件代码中不起眼的位置上放置权利人标记是一种常用的保护自己的方法,因为软件代码非常多,这个时候你在其中的某个位置上写一个“某某公司出品”字样,别人很难注意到,如果鉴定同一性的时候发现了这个字样出现在对方程序中,抄袭就变得显而易见了。
(3)常用的字符串出现的位置和频率。比如,空格键、回车键等,这个关系到开发者编写程序的习惯问题,如果两个程序中这些常用的字符串出现的位置和频率都一样,也会作为一个很重要的判断的维度,因为就算两个不同的开发者同时想到了一个编码逻辑,也不太可能在编写每句代码的时候使用的段落、字符都完全一样。就好像我们都想到了一个故事情节,但写出来的小说不可能连标点符号都一致。
了解到这些跟技术相关的原理,我们就知道如何从法律层面进攻和防御了,面对鉴定机构出具的鉴定报告,你也可以从这些维度上对鉴定意见进行质疑,指出鉴定意见中不合理的部分。
最后是软件的源代码和前端最终成品表达之间的脱节问题,这个问题在游戏软件上表现得最为突出。游戏软件通常是由一个软件加一个素材库组成的,软件只是作为调度素材库中各种角色、任务、效果的流程而已,整个游戏在用户感知层面更多的是接触到了素材库中的素材,并且当游戏真正执行的时候,往往是软件动态调用素材后形成的视频流,所以这个时候如何确定游戏作品所保护的对象,以及如何进行侵权比对认定都成为一个复杂的问题。
实践中甚至出现了,游戏作品前端展现的效果高度一致,但后端的代码明显不同的情况,越来越多的权利人主张按照视听作品保护游戏并非没有道理,但视听作品有时候过分依赖游戏表现出来的效果,对静态的代码又力有不逮,所以有业内人士提出应将游戏作品作为著作权法中一种新的作品类型加以规定,这些问题非常值得深入探讨。
[1] 图片来源:https://pixabay.com/zh/illustrations/molecule-cell-biology-molecular-2082634/,最后访问时间:2022年7月10日。