渾儀ARMILLARY

文章 · JOURNAL

怎麼自己驗算一張星盤:
計算收據與卷宗

排盤結果怎麼確認?與其相信畫面上精確到角秒的數字,不如看它是怎麼算出來的。這篇帶你讀渾儀每張星盤附的計算收據,請別人用同一份輸入重算來比對,並說清楚收據說得出什麼、說不出什麼。

渾儀每張星盤都附一份計算收據:寫出鐘面時間怎麼換算、用了哪一版程式與哪些星曆檔,以及整串計算步驟的雜湊。用同一份輸入再算一次、比對這串雜湊:兩串相同,兩次的計算軌跡就一模一樣。

排盤軟體給的數字通常看起來都很確定,精確到角分甚至角秒。可是同一個出生時間,換一個網站,結果可能差一點:時區、夏令時間、宮位制、預設選項,任何一項不同,結果就不同。要知道差在哪裡,得先看得到每一步;本站的收據就是為了這件事。

重點

  • 收據在計算頁結果最下方的「技術細節與驗算資料」裡;打開時,頁面用同一份輸入請伺服器再算一次,伺服器不保存任何資料[1]。
  • 收據寫出版本、時間換算的每一個中間值、星曆檔的雜湊與一串軌跡雜湊;軌跡的第一步就是你送出的全部選項,所以任何一個選項改了,雜湊就不同[2]。
  • 兩份結果的雜湊相同,代表兩次走過的每一步都一樣;但它不是簽章,收據自己就寫著它「只能偵測意外損壞,不證明來源,也不證明沒被刻意修改」,也不跨電腦、跨程式語言通用[2][4]。
  • 要把線上網站對回公開原始碼,看收據上的發布識別,再照〈安全〉的步驟重算前端的雜湊[3]。

§01收據在哪裡、什麼時候產生

在計算頁算完一張盤,結果最下方有一區「技術細節與驗算資料」。平常的結果只帶畫面要畫的欄位;你打開這一區,或在匯出選「運算結果+驗算資料」時,頁面才把同一份輸入再送一次,請伺服器重算,回來的完整版多了四樣東西:本次請求的選項、逐步計算軌跡、輸出契約,以及計算收據[1]。

星盤是伺服器算的,收據也是伺服器在同一次計算裡寫的,不是你的瀏覽器事後拼出來的。伺服器算完就把回應送回來,計算期間不寫檔,也不把出生資料寫進日誌;收據之後只在你這個分頁的記憶體裡,直到你關掉分頁或按「清除」[3]。下載匯出檔是你自己按下的本機寫入,寫到你的電腦上之後,本站就收不回來了。

這裡已經用到收據一次:第二次算回來的完整版,頁面會先拿它的軌跡雜湊、建置識別與每一區結果,和畫面上那一份逐一比對;不一致,就不接上去,改顯示「驗算資料與畫面上的結果對不上,可能是服務在兩次請求之間更新了。」[1]頁面只把對得上的那一份接到結果底下。

§02讀一張收據

圖 1 是一張合成星盤的收據,摘出五組。日期、時刻與座標都是測試用的,不對應任何真實的人;圖上的每一個字,都是結果頁的程式讀同一份回應印出來的。指著任一組,下面會寫出那一組在說什麼。

一張合成星盤的計算收據:版本、時間換算、星曆檔、軌跡雜湊與隱私聲明 ①版本與來源哪一版程式、哪一版星曆函式庫算的API schema0.18.0Calculation Dossier0.10.0建置識別未提供(此建置沒有注入原始碼修訂)pyswisseph2.10.3.2Swiss Ephemeris2.10.03 ②時間換算鐘面時間怎麼一步步換成天文計算用的時間本地時間1990-05-15 14:30:00.000時區臺北(Asia/Taipei)UTC 偏移UTC+08:00UTC1990-05-15 06:30:00.000儒略日 JD(UT)2448026.770834ΔT(秒)57.105 ③星曆檔(在匯出的卷宗裡)讀了哪幾個資料檔,位元組和釘選的一不一樣sepl_18.se1ca1393ceab3a44fb… 符合釘選值semo_18.se11ca07bd67c24374d… 符合釘選值 ④軌跡收據整串計算步驟的指紋:只要一步不同,它就不同逐步軌跡步數23SHA-2560ae456efaf523f9fd18995aaadc80a47dcb02e6632036d7ac8e1897a946ac1b1跨語言可攜否(僅供偵測意外損壞) ⑤隱私聲明提醒你:這份收據含有出生資料含敏感出生資料是可匿名分享否 ①版本與來源哪一版程式、哪一版星曆函式庫算的API schema0.18.0Calculation Dossier0.10.0建置識別未提供(此建置沒有注入原始碼修訂)pyswisseph2.10.3.2Swiss Ephemeris2.10.03 ②時間換算鐘面時間怎麼一步步換成天文計算用的時間本地時間1990-05-15 14:30:00.000時區臺北(Asia/Taipei)UTC 偏移UTC+08:00UTC1990-05-15 06:30:00.000儒略日 JD(UT)2448026.770834ΔT(秒)57.105 ③星曆檔(在匯出的卷宗裡)讀了哪幾個資料檔,位元組和釘選的一不一樣sepl_18.se1ca1393ceab3a44fb… 符合釘選值semo_18.se11ca07bd67c24374d… 符合釘選值 ④軌跡收據整串計算步驟的指紋:只要一步不同,它就不同逐步軌跡步數23SHA-2560ae456efaf523f9fd18995aaadc80a47dcb02e6632036d7ac8e1897a946ac1b1跨語言可攜否(僅供偵測意外損壞) ⑤隱私聲明提醒你:這份收據含有出生資料含敏感出生資料是可匿名分享否
圖 1一張合成星盤(不是任何人的出生資料:1990 年 5 月 15 日 14:30,北緯 22.9908 度、東經 120.2133 度,臺北時區)的計算收據,摘出五組。①②④⑤是結果頁「技術細節與驗算資料」裡〈計算收據〉印的原字,③是匯出的卷宗 JSON 裡的星曆檔紀錄;星曆檔的雜湊只印開頭,完整值在匯出的卷宗裡;軌跡雜湊在圖上分成兩行,表格裡是一整串。
收據上的值(表格,軌跡雜湊不截短)
項目數值
① API schema0.18.0
① Calculation Dossier0.10.0
① 建置識別未提供(此建置沒有注入原始碼修訂)
① pyswisseph2.10.3.2
① Swiss Ephemeris2.10.03
② 本地時間1990-05-15 14:30:00.000
② 時區臺北(Asia/Taipei)
② UTC 偏移UTC+08:00
② UTC1990-05-15 06:30:00.000
② 儒略日 JD(UT)2448026.770834
② ΔT(秒)57.105
③ sepl_18.se1(SHA-256 開頭)ca1393ceab3a44fb… 符合釘選值
③ semo_18.se1(SHA-256 開頭)1ca07bd67c24374d… 符合釘選值
④ 逐步軌跡步數23
④ 序列化雜湊 SHA-2560ae456efaf523f9fd18995aaadc80a47dcb02e6632036d7ac8e1897a946ac1b1
④ 跨語言可攜否(僅供偵測意外損壞)
⑤ 含敏感出生資料是
⑤ 可匿名分享否

① 版本與來源。回應格式與計算卷宗(Calculation Dossier,本站把一次計算的輸入、設定、版本與證據收在一起的那一份紀錄)各有版號,算行星位置的是 Swiss Ephemeris 2.10.03。線上的收據在這一組還會印出這次用的程式修訂與發布識別;圖 1 的範例是在本機產生的,所以寫「未提供」。§05 再回來說它怎麼用。

② 時間換算。你輸入的是出生紀錄上的鐘面時間,星曆要的是天文時間。收據把中間每一步都寫出來:用了哪個時區、偏移多少(這張是 UTC+08:00)、換成的世界時(UTC),再換成儒略日(Julian Day,天文學用來連續計日的日數,這張是 2448026.770834),以及這一刻地球自轉與均勻時間的差 ΔT(Delta T,這張是 57.105 秒)。逐步計算軌跡的第 2 到第 4 步,從「本地時間 -> UTC」開始,寫的是同一段換算的算式與完整精度[2]。時區與夏令時間這一步最常出錯,背景見〈臺灣夏令時間出生,排盤要減一小時嗎?〉;為什麼不必先換成真太陽時,見〈西洋占星要不要換真太陽時?〉。

③ 星曆檔。星曆(ephemeris)是行星位置表。這張盤需要 sepl_18.se1、semo_18.se1 兩個檔:前者是行星,後者是月亮,資料源自 JPL DE441(美國噴射推進實驗室的星曆)。畫面上的收據只寫這條譜系;匯出的卷宗另外列出每個檔的大小、SHA-256 雜湊,以及它和本站固定在程式庫裡的雜湊是否相符。相符只代表檔案的位元組沒有被換過,不代表天文上正確[2];天文上準不準,是〈驗證〉那一頁回答的問題。

④ 軌跡收據。逐步計算軌跡(calculation trace)把這次的計算拆成一步一步,每一步列出算式、輸入與結果,這張軌跡共 23 步。收據上的 SHA-256 雜湊(hash,把一大段資料壓成一串固定長度的指紋)就是對整份軌跡算的。軌跡的第一步是「請求選項」,裡面是這次送出的全部選項,連你沒動、由伺服器帶入的預設值也在內[2]。

⑤ 隱私聲明。「含敏感出生資料:是」「可匿名分享:否」。收據與卷宗裡有出生日期、時刻與座標;這一行是提醒你,要傳給別人之前想一下。聲明狀態寫的是「自我聲明,尚待外部審查」,不是任何第三方認證。

§03軌跡雜湊綁住了什麼

雜湊的性質很簡單:輸入完全相同,得到同一串;輸入差一個字,整串就換掉。圖 2 把圖 1 那個請求送給本站的計算服務,再分別改一個輸入各送一次。按鈕選改法,右欄打了交叉線的是和原本不同的那幾列:

改一個輸入,收據上哪幾行會變 收據與結果的一行原本改了一個輸入之後比較本地時間1990-05-15 14:30:00.0001990-05-15 14:30:00.000相同1990-05-15 14:30:01.000不同1990-05-15 14:30:00.000相同1990-05-15 14:30:00.000相同UTC1990-05-15 06:30:00.0001990-05-15 06:30:00.000相同1990-05-15 06:30:01.000不同1990-05-15 06:30:00.000相同1990-05-15 06:30:00.000相同儒略日 JD(UT)2448026.7708342448026.770834相同2448026.770846不同2448026.770834相同2448026.770834相同上升點天秤座 0°24′31.27″天秤座 0°24′31.27″相同天秤座 0°24′45.11″不同天秤座 0°24′31.27″相同天秤座 0°24′31.27″相同第 2 宮起點天蠍座 0°00′00.00″天蠍座 0°00′00.00″相同天蠍座 0°00′00.00″相同天秤座 29°16′56.81″不同天蠍座 0°00′00.00″相同軌跡步數2323相同23相同22不同23相同軌跡雜湊0ae456efaf523f9f…同一串相同另一串不同另一串不同另一串不同 每一列:原本/改了之後本地時間原本1990-05-15 14:30:00.000改了1990-05-15 14:30:00.000相同1990-05-15 14:30:01.000不同1990-05-15 14:30:00.000相同1990-05-15 14:30:00.000相同UTC原本1990-05-15 06:30:00.000改了1990-05-15 06:30:00.000相同1990-05-15 06:30:01.000不同1990-05-15 06:30:00.000相同1990-05-15 06:30:00.000相同儒略日 JD(UT)原本2448026.770834改了2448026.770834相同2448026.770846不同2448026.770834相同2448026.770834相同上升點原本天秤座 0°24′31.27″改了天秤座 0°24′31.27″相同天秤座 0°24′45.11″不同天秤座 0°24′31.27″相同天秤座 0°24′31.27″相同第 2 宮起點原本天蠍座 0°00′00.00″改了天蠍座 0°00′00.00″相同天蠍座 0°00′00.00″相同天秤座 29°16′56.81″不同天蠍座 0°00′00.00″相同軌跡步數原本23改了23相同23相同22不同23相同軌跡雜湊原本0ae456efaf523f9f…改了同一串相同另一串不同另一串不同另一串不同
圖 2把圖 1 那個請求送給本站的計算服務,再分別改一個輸入送一次。按鈕選改法,右欄的排線格是和原本不同的那幾列。「原樣再算一次」每一列都相同,雜湊也相同;只改一個沒有用到的選項,所有數字都不變,只有雜湊不同。圖上的雜湊只比相同或不同:同一個請求在不同的電腦上算,雜湊可能不一樣(見內文),所以這裡只印出圖 1 那一份的開頭。
四種改法的每一列(表格)
項目原本原樣再算一次出生時刻多一秒宮位制改成 Placidus改一個沒用到的選項
本地時間1990-05-15 14:30:00.0001990-05-15 14:30:00.0001990-05-15 14:30:01.000(不同)1990-05-15 14:30:00.0001990-05-15 14:30:00.000
UTC1990-05-15 06:30:00.0001990-05-15 06:30:00.0001990-05-15 06:30:01.000(不同)1990-05-15 06:30:00.0001990-05-15 06:30:00.000
儒略日 JD(UT)2448026.7708342448026.7708342448026.770846(不同)2448026.7708342448026.770834
上升點天秤座 0°24′31.27″天秤座 0°24′31.27″天秤座 0°24′45.11″(不同)天秤座 0°24′31.27″天秤座 0°24′31.27″
第 2 宮起點天蠍座 0°00′00.00″天蠍座 0°00′00.00″天蠍座 0°00′00.00″天秤座 29°16′56.81″(不同)天蠍座 0°00′00.00″
軌跡步數23232322(不同)23
軌跡雜湊0ae456efaf523f9f…同一串另一串(不同)另一串(不同)另一串(不同)

四種改法各說明一件事。原樣再算一次,每一列都相同,雜湊也相同:同一個輸入、同一版程式,算出同一串。出生時刻多一秒,圖上時間換算的三列都動了,上升點也跟著走了十幾角秒,雜湊整串換掉。宮位制改成 Placidus,時間與上升點都不變,第二宮的起點換了,軌跡也少了一步。最值得看的是改一個沒用到的選項:這次沒有算赤緯相位,所以改它的容許度,任何一個結果都不會變;但它寫在軌跡第一步,雜湊還是不同。這正是設計的用意:雜湊相同,代表連「請求了什麼」都相同,不只是剛好算出一樣的數字。

雜湊也有它的界線,收據上「跨語言可攜:否」說的就是這件事。

  • 它不是簽章。任何人改了軌跡,都可以替改過的軌跡重算一串新的雜湊。收據上的說明是:只能偵測意外損壞,不證明來源,也不證明沒被刻意修改[2]。
  • 它綁的是一種特定寫法。雜湊是對 Python 把軌跡寫成文字的結果算的。瀏覽器寫 JSON 的方式不同,例如會把 1.0 寫成 1;我把匯出檔照瀏覽器的寫法讀回 Python 重算,得到的是另一串[4]。所以不要拿下載的檔案自己重算雜湊來比,要比的是兩次計算各自回報的雜湊。
  • 它不含版本。雜湊只對軌跡算,不包括「版本與來源」那幾列。兩個版本的程式剛好算出一樣的軌跡,雜湊也會一樣;是哪一版算的,要另外看版本那一組。
  • 它跟著機器走。同一份程式在不同的電腦上執行,浮點數的最後幾位可能不同:本站的測試資料在 macOS 上產生、在 Linux 上重播,兩邊的數值只在最後幾位小數不同,雜湊就可能整串不同。所以本站自己的測試也不直接比這串雜湊,而是各自重算再核對[4]。拿同一個網站算兩次來比,這不是問題;拿自己架的一份去比線上的,要比數值,不要比雜湊。
要記住的一句

兩份收據的軌跡雜湊相同,代表兩次的請求與每一步的數字都一樣。它說的是「兩次一樣」,不是「算得對」,也不說是哪一版程式算的。

§04請別人用你的卷宗重算一次

收據最有用的時候,是你想請另一個人確認:「你算的和我算的,是同一個計算嗎?」做法是:

  1. 在計算頁匯出「運算結果+驗算資料」(JSON 或 Markdown)。卷宗裡的「已驗證的輸入」有日期、含秒的時刻、時區、座標、海拔、出生時刻把握程度與計算模式;〈本次請求的選項〉列出全部選項,含伺服器帶入的預設[1]。
  2. 對方在計算頁選「自訂」,照著填:地點用「改為手動輸入座標與時區」,座標照卷宗的位數填;選項照〈本次請求的選項〉一項一項對。
  3. 對方算完,打開「技術細節與驗算資料」,看〈計算收據〉裡的軌跡雜湊。和你的一樣,兩次的軌跡就一模一樣;再對一下「版本與來源」,看兩次是不是同一版程式。
  4. 不一樣時,依序找原因:先比「版本與來源」,兩次可能隔著一次網站更新;再比〈本次請求的選項〉;最後打開〈逐步計算軌跡〉,從第一步往下對,第一個不同的那一步就是差異的起點。軌跡每一步都可以複製出來對照。

這裡要先想一件事:卷宗裡有你的出生日期、時刻與座標,傳給別人就是把這些交給對方。如果只是想試試這套流程,計算頁有一顆「載入合成範例(不是真實生辰)」按鈕,填的就是圖 1 的日期、時刻與座標,兩個人各算一次就能比。至於要不要拿自己的盤請人核對,由你決定。

你在線上算出的雜湊,不一定和圖 1 的一樣:版本不同、選項不同,或是線上服務跑在不同的機器上,都會讓它不同。要比的是你和對方在同一個網站上的兩次結果。

§05把線上的網站對回公開原始碼

前面比的是「兩次一樣」。另一個問題是:線上跑的,真的是公開的那份程式嗎?本站的原始碼公開在 github.com/sa3952/Armillary。線上的收據在「版本與來源」那一組會多出幾列:組合發布識別、後端映像的識別碼、前端發佈的雜湊,以及兩者各自對應的公開原始碼修訂與網址[1]。

前端是在你瀏覽器裡執行的那部分程式,任何人都能從那個修訂的公開原始碼重算出同一個雜湊,和收據上的值比對;指令與步驟寫在〈安全〉第 01 節第七項。後端的映像不是逐位元可以重現的,對應方式是鎖定雜湊的相依套件與映像內的檔案清單,同一節也寫了界線[3]。至於瀏覽器實際送出哪些請求、有沒有留下 cookie,〈親手驗證本站的隱私說明〉一頁教你用開發者工具親眼看。

§06收據說不出什麼

收據是這一次計算的可重現證據。它說得出用了哪一版、哪些檔、哪些選項、每一步怎麼算;它說不出這些步驟在天文上準不準,那要靠和另一條獨立計算管線的比對(〈驗證〉);也說不出伺服器在你看不到的地方做了什麼,那要靠公開的原始碼與設定(〈安全〉)。收據只說明怎麼算;不替你解盤,也不預測。

§07常見問題

星盤要怎麼驗算?

打開計算頁結果最下方的「技術細節與驗算資料」,看〈計算收據〉與〈逐步計算軌跡〉。用同一份輸入再算一次,兩次的軌跡雜湊相同,兩次的軌跡就一模一樣;要逐步核對,軌跡每一步都列出算式、輸入與結果。

排盤結果怎麼確認是對的?

分兩件事。「這次怎麼算的」看收據:時區、世界時、儒略日、版本、選項都寫在上面,可以和別的工具逐項對照。「算得準不準」看〈驗證〉頁,那是和另一條獨立計算管線比對的結果,範圍與界線都寫在那裡。

雜湊一樣代表什麼?

代表兩次計算的請求與每一步都相同。它不是簽章,不證明來源,不包含版本,也不證明天文上正確。

收據會存在伺服器上嗎?

不會。伺服器算完就把回應送回你的瀏覽器,計算期間不寫檔,日誌也沒有出生資料的欄位;收據只在你的分頁裡,關掉分頁或按「清除」就沒了。你下載的匯出檔則存在你自己的電腦上。

可以把卷宗傳給別人幫我驗算嗎?

可以,但卷宗裡有出生日期、時刻與座標。只想試流程的話,用計算頁的合成範例。

出處

每一條後面標明我們核到哪一層:本站出處清單是本站公開、可以逐行核對的頁面與原始碼;本站自算是我們用標明版本的程式算出、可以照著重算的結果。

  1. 渾儀計算頁的「技術細節與驗算資料」與「運算結果+驗算資料」匯出:第二次請求、與畫面上那一份的比對、收據各表的欄位,由公開原始碼的 frontend/zh-TW/calculate.js、view-model.js、exporters.js 產生。本站出處清單
  2. 本站計算服務回應裡的計算卷宗:trace_receipt(步數、SHA-256、序列化方法與「跨語言可攜:否」)、engine(星曆檔的大小、雜湊與是否符合釘選值)、time_conversion,以及逐步計算軌跡的第一步「請求選項」。可在計算頁選「運算結果+驗算資料」匯出後查看。本站出處清單
  3. 渾儀〈安全〉第 01 節第七項〈線上版本對得回公開原始碼〉(前端發佈雜湊的重算指令與後端的界線)與第 02 節〈出生資料的完整路徑〉(計算期間不寫檔、日誌欄位與「不是安全抹除」的界線);〈親手驗證本站的隱私說明〉第 04 節(分頁記憶體與瀏覽器儲存)。本站出處清單
  4. 兩項本站自己的核對。其一,2026 年 10 月我以本機的同版服務重做:圖 1 那份回應以 Node.js 的 JSON.parse/JSON.stringify 讀寫一次後,照收據的序列化方法(Python json.dumps,鍵排序、無空白、UTF-8)重算,雜湊與原本不同。其二,本站前端測試資料的比對程式記載:測試資料在 macOS(arm64)產生、在 Linux(x86_64)重播,兩邊的 Swiss Ephemeris 建置在浮點數的最後幾位不同,所以那個比對只核對各自的雜湊是否綁住自己的軌跡,不比對兩邊的雜湊;這個比對程式不在公開原始碼裡。本站自算

算一張盤,
打開它的收據看一次。

按「載入合成範例」再按「計算」,打開結果最下方的「技術細節與驗算資料」。再算一次,比比兩次的軌跡雜湊。

排一張盤 →

延伸閱讀